diff --git a/bin/unshuffle_list.txt b/bin/unshuffle_list.txt
index 21945a93a71..36ad8feabc4 100644
--- a/bin/unshuffle_list.txt
+++ b/bin/unshuffle_list.txt
@@ -58,7 +58,6 @@ src/jdk.compiler : jdk/src/jdk.compiler langtools/src/jdk.compiler
src/jdk.crypto.cryptoki : jdk/src/jdk.crypto.cryptoki
src/jdk.crypto.ec : jdk/src/jdk.crypto.ec
src/jdk.crypto.mscapi : jdk/src/jdk.crypto.mscapi
-src/jdk.crypto.ucrypto : jdk/src/jdk.crypto.ucrypto
src/jdk.dynalink : nashorn/src/jdk.dynalink
src/jdk.editpad : jdk/src/jdk.editpad
src/jdk.hotspot.agent : hotspot/src/jdk.hotspot.agent
@@ -101,13 +100,11 @@ src/jdk.zipfs : jdk/src/jdk.zipfs
src/langtools/sample : langtools/src/sample
src/linux : jdk/src/linux
src/sample : jdk/src/sample
-src/solaris : jdk/src/solaris
src/hotspot/share : hotspot/src/share/vm
src/hotspot/cpu/aarch64 : hotspot/src/cpu/aarch64/vm
src/hotspot/cpu/arm : hotspot/src/cpu/arm/vm
src/hotspot/cpu/ppc : hotspot/src/cpu/ppc/vm
src/hotspot/cpu/s390 : hotspot/src/cpu/s390/vm
-src/hotspot/cpu/sparc : hotspot/src/cpu/sparc/vm
src/hotspot/cpu/x86 : hotspot/src/cpu/x86/vm
src/hotspot/cpu/zero : hotspot/src/cpu/zero/vm
src/hotspot/os/aix : hotspot/src/os/aix/vm
@@ -115,7 +112,6 @@ src/hotspot/os/bsd : hotspot/src/os/bsd/vm
src/hotspot/os/linux : hotspot/src/os/linux/vm
src/hotspot/os/posix/dtrace : hotspot/src/os/posix/dtrace
src/hotspot/os/posix : hotspot/src/os/posix/vm
-src/hotspot/os/solaris : hotspot/src/os/solaris/vm
src/hotspot/os/windows : hotspot/src/os/windows/vm
src/hotspot/os_cpu/aix_ppc : hotspot/src/os_cpu/aix_ppc/vm
src/hotspot/os_cpu/bsd_x86 : hotspot/src/os_cpu/bsd_x86/vm
@@ -124,11 +120,8 @@ src/hotspot/os_cpu/linux_aarch64 : hotspot/src/os_cpu/linux_aarch64/vm
src/hotspot/os_cpu/linux_arm : hotspot/src/os_cpu/linux_arm/vm
src/hotspot/os_cpu/linux_ppc : hotspot/src/os_cpu/linux_ppc/vm
src/hotspot/os_cpu/linux_s390 : hotspot/src/os_cpu/linux_s390/vm
-src/hotspot/os_cpu/linux_sparc : hotspot/src/os_cpu/linux_sparc/vm
src/hotspot/os_cpu/linux_x86 : hotspot/src/os_cpu/linux_x86/vm
src/hotspot/os_cpu/linux_zero : hotspot/src/os_cpu/linux_zero/vm
-src/hotspot/os_cpu/solaris_sparc : hotspot/src/os_cpu/solaris_sparc/vm
-src/hotspot/os_cpu/solaris_x86 : hotspot/src/os_cpu/solaris_x86/vm
src/hotspot/os_cpu/windows_x86 : hotspot/src/os_cpu/windows_x86/vm
src/hotspot : hotspot/src
src/utils/IdealGraphVisualizer : hotspot/src/share/tools/IdealGraphVisualizer
diff --git a/doc/building.html b/doc/building.html
index 0fd6c117fee..e0cca9534bd 100644
--- a/doc/building.html
+++ b/doc/building.html
@@ -30,13 +30,11 @@
Build Hardware Requirements
Operating System Requirements
@@ -157,18 +154,15 @@
The JDK is a massive project, and require machines ranging from decent to powerful to be able to build in a reasonable amount of time, or to be able to complete a build at all.
We strongly recommend usage of an SSD disk for the build, since disk speed is one of the limiting factors for build performance.
Building on x86
-At a minimum, a machine with 2-4 cores is advisable, as well as 2-4 GB of RAM. (The more cores to use, the more memory you need.) At least 6 GB of free disk space is required (8 GB minimum for building on Solaris).
+At a minimum, a machine with 2-4 cores is advisable, as well as 2-4 GB of RAM. (The more cores to use, the more memory you need.) At least 6 GB of free disk space is required.
Even for 32-bit builds, it is recommended to use a 64-bit build machine, and instead create a 32-bit target using --with-target-bits=32
.
-Building on sparc
-At a minimum, a machine with 4 cores is advisable, as well as 4 GB of RAM. (The more cores to use, the more memory you need.) At least 8 GB of free disk space is required.
-Note: The sparc port is deprecated.
Building on aarch64
At a minimum, a machine with 8 cores is advisable, as well as 8 GB of RAM. (The more cores to use, the more memory you need.) At least 6 GB of free disk space is required.
If you do not have access to sufficiently powerful hardware, it is also possible to use cross-compiling.
Building on 32-bit arm
This is not recommended. Instead, see the section on Cross-compiling.
Operating System Requirements
-The mainline JDK project supports Linux, Solaris, macOS, AIX and Windows. Support for other operating system, e.g. BSD, exists in separate "port" projects.
+The mainline JDK project supports Linux, macOS, AIX and Windows. Support for other operating system, e.g. BSD, exists in separate "port" projects.
In general, the JDK can be built on a wide range of versions of these operating systems, but the further you deviate from what is tested on a daily basis, the more likely you are to run into problems.
This table lists the OS versions used by Oracle when building the JDK. Such information is always subject to change, but this table is up to date at the time of writing.
@@ -184,20 +178,16 @@
Oracle Enterprise Linux 6.4 / 7.6 |
-Solaris |
-Solaris 11.3 SRU 20 |
-
-
macOS |
Mac OS X 10.13 (High Sierra) |
-
+
Windows |
Windows Server 2012 R2 |
-The double version numbers for Linux and Solaris are due to the hybrid model used at Oracle, where header files and external libraries from an older version are used when building on a more modern version of the OS.
+The double version numbers for Linux are due to the hybrid model used at Oracle, where header files and external libraries from an older version are used when building on a more modern version of the OS.
The Build Group has a wiki page with Supported Build Platforms. From time to time, this is updated by contributors to list successes or failures of building on different platforms.
Windows
Windows XP is not a supported platform, but all newer Windows should be able to build the JDK.
@@ -223,10 +213,6 @@
It's possible to build both Windows and Linux binaries from WSL. To build Windows binaries, you must use a Windows boot JDK (located in a Windows-accessible directory). To build Linux binaries, you must use a Linux boot JDK. The default behavior is to build for Windows. To build for Linux, pass --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu
to configure
.
If building Windows binaries, the source code must be located in a Windows- accessible directory. This is because Windows executables (such as Visual Studio and the boot JDK) must be able to access the source code. Also, the drive where the source is stored must be mounted as case-insensitive by changing either /etc/fstab or /etc/wsl.conf in WSL. Individual directories may be corrected using the fsutil tool in case the source was cloned before changing the mount options.
Note that while it's possible to build on WSL, testing is still not fully supported.
-Solaris
-See make/devkit/solaris11.1-package-list.txt
for a list of recommended packages to install when building on Solaris. The versions specified in this list is the versions used by the daily builds at Oracle, and is likely to work properly.
-Older versions of Solaris shipped a broken version of objcopy
. At least version 2.21.1 is needed, which is provided by Solaris 11 Update 1. Objcopy is needed if you want to have external debug symbols. Please make sure you are using at least version 2.21.1 of objcopy, or that you disable external debug symbols.
-Note: The Solaris port is deprecated.
macOS
Apple is using a quite aggressive scheme of pushing OS updates, and coupling these updates with required updates of Xcode. Unfortunately, this makes it difficult for a project such as the JDK to keep pace with a continuously updated machine running macOS. See the section on Apple Xcode on some strategies to deal with this.
It is recommended that you use at least Mac OS X 10.13 (High Sierra). At the time of writing, the JDK has been successfully compiled on macOS 10.12 (Sierra).
@@ -259,14 +245,10 @@
Apple Xcode (using clang) |
-Solaris |
-Oracle Solaris Studio |
-
-
AIX |
IBM XL C/C++ |
-
+
Windows |
Microsoft Visual Studio |
@@ -290,10 +272,6 @@
Apple Xcode 10.1 (using clang 10.0.0) |
-Solaris |
-Oracle Solaris Studio 12.6 (with compiler version 5.15) |
-
-
Windows |
Microsoft Visual Studio 2019 update 16.5.3 |
@@ -313,64 +291,6 @@
xcode-select --install
It is advisable to keep an older version of Xcode for building the JDK when updating Xcode. This blog page has good suggestions on managing multiple Xcode versions. To use a specific version of Xcode, use xcode-select -s
before running configure
, or use --with-toolchain-path
to point to the version of Xcode to use, e.g. configure --with-toolchain-path=/Applications/Xcode8.app/Contents/Developer/usr/bin
If you have recently (inadvertently) updated your OS and/or Xcode version, and the JDK can no longer be built, please see the section on Problems with the Build Environment, and Getting Help to find out if there are any recent, non-merged patches available for this update.
-Oracle Solaris Studio
-The minimum accepted version of the Solaris Studio compilers is 5.13 (corresponding to Solaris Studio 12.4). Older versions will not be accepted by configure.
-The Solaris Studio installation should contain at least these packages:
-
-
-
-
-
-
-developer/solarisstudio-124/backend |
-12.4-1.0.6.0 |
-
-
-developer/solarisstudio-124/c++ |
-12.4-1.0.10.0 |
-
-
-developer/solarisstudio-124/cc |
-12.4-1.0.4.0 |
-
-
-developer/solarisstudio-124/library/c++-libs |
-12.4-1.0.10.0 |
-
-
-developer/solarisstudio-124/library/math-libs |
-12.4-1.0.0.1 |
-
-
-developer/solarisstudio-124/library/studio-gccrt |
-12.4-1.0.0.1 |
-
-
-developer/solarisstudio-124/studio-common |
-12.4-1.0.0.1 |
-
-
-developer/solarisstudio-124/studio-ja |
-12.4-1.0.0.1 |
-
-
-developer/solarisstudio-124/studio-legal |
-12.4-1.0.0.1 |
-
-
-developer/solarisstudio-124/studio-zhCN |
-12.4-1.0.0.1 |
-
-
-
-Compiling with Solaris Studio can sometimes be finicky. This is the exact version used by Oracle, which worked correctly at the time of writing:
-$ cc -V
-cc: Sun C 5.13 SunOS_i386 2014/10/20
-$ CC -V
-CC: Sun C++ 5.13 SunOS_i386 151846-10 2015/10/30
Microsoft Visual Studio
The minimum accepted version of Visual Studio is 2010. Older versions will not be accepted by configure
. The maximum accepted version of Visual Studio is 2019. Versions older than 2017 are unlikely to continue working for long.
If you have multiple versions of Visual Studio installed, configure
will by default pick the latest. You can request a specific version to be used by setting --with-toolchain-version
, e.g. --with-toolchain-version=2015
.
@@ -394,7 +314,6 @@ CC: Sun C++ 5.13 SunOS_i386 151846-10 2015/10/30
- To install on an apt-based Linux, try running
sudo apt-get install libfreetype6-dev
.
- To install on an rpm-based Linux, try running
sudo yum install freetype-devel
.
-- To install on Solaris, try running
pkg install system/library/freetype-2
.
Use --with-freetype-include=<path>
and --with-freetype-lib=<path>
if configure
does not automatically locate the platform FreeType files.
CUPS
@@ -402,15 +321,13 @@ CC: Sun C++ 5.13 SunOS_i386 151846-10 2015/10/30
- To install on an apt-based Linux, try running
sudo apt-get install libcups2-dev
.
- To install on an rpm-based Linux, try running
sudo yum install cups-devel
.
-- To install on Solaris, try running
pkg install print/cups
.
Use --with-cups=<path>
if configure
does not properly locate your CUPS files.
X11
-Certain X11 libraries and include files are required on Linux and Solaris.
+Certain X11 libraries and include files are required on Linux.
- To install on an apt-based Linux, try running
sudo apt-get install libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev
.
- To install on an rpm-based Linux, try running
sudo yum install libXtst-devel libXt-devel libXrender-devel libXrandr-devel libXi-devel
.
-- To install on Solaris, try running
pkg install x11/header/x11-protocols x11/library/libice x11/library/libpthread-stubs x11/library/libsm x11/library/libx11 x11/library/libxau x11/library/libxcb x11/library/libxdmcp x11/library/libxevie x11/library/libxext x11/library/libxrender x11/library/libxrandr x11/library/libxscrnsaver x11/library/libxtst x11/library/toolkit/libxt
.
Use --with-x=<path>
if configure
does not properly locate your X11 files.
ALSA
@@ -443,7 +360,6 @@ CC: Sun C++ 5.13 SunOS_i386 151846-10 2015/10/30
At least version 3.81 of GNU Make must be used. For distributions supporting GNU Make 4.0 or above, we strongly recommend it. GNU Make 4.0 contains useful functionality to handle parallel building (supported by --with-output-sync
) and speed and stability improvements.
Note that configure
locates and verifies a properly functioning version of make
and stores the path to this make
binary in the configuration. If you start a build using make
on the command line, you will be using the version of make found first in your PATH
, and not necessarily the one stored in the configuration. This initial make will be used as "bootstrap make", and in a second stage, the make located by configure
will be called. Normally, this will present no issues, but if you have a very old make
, or a non-GNU Make make
in your path, this might cause issues.
If you want to override the default make found by configure
, use the MAKE
configure variable, e.g. configure MAKE=/opt/gnu/make
.
-On Solaris, it is common to call the GNU version of make by using gmake
.
GNU Bash
The JDK requires GNU Bash. No other shells are supported.
At least version 3.2 of GNU Bash must be used.
@@ -865,9 +781,6 @@ Clock skew detected. Your build may be incomplete.
then the clock on your build machine is out of sync with the timestamps on the source files. Other errors, apparently unrelated but in fact caused by the clock skew, can occur along with the clock skew warnings. These secondary errors may tend to obscure the fact that the true root cause of the problem is an out-of-sync clock.
If you see these warnings, reset the clock on the build machine, run make clean
and restart the build.
Out of Memory Errors
-On Solaris, you might get an error message like this:
-Trouble writing out table to disk
-To solve this, increase the amount of swap space on your build machine.
On Windows, you might get error messages like this:
fatal error - couldn't allocate heap
cannot create ... Permission denied
@@ -919,7 +832,7 @@ sudo mv /tmp/configure /usr/local/bin
If you are prepared to take some risk of an incorrect build, and know enough of the system to understand how things build and interact, you can speed up the build process considerably by instructing make to only build a portion of the product.
Building Individual Modules
The safe way to use fine-grained make targets is to use the module specific make targets. All source code in the JDK is organized so it belongs to a module, e.g. java.base
or jdk.jdwp.agent
. You can build only a specific module, by giving it as make target: make jdk.jdwp.agent
. If the specified module depends on other modules (e.g. java.base
), those modules will be built first.
-You can also specify a set of modules, just as you can always specify a set of make targets: make jdk.crypto.cryptoki jdk.crypto.ec jdk.crypto.mscapi jdk.crypto.ucrypto
+You can also specify a set of modules, just as you can always specify a set of make targets: make jdk.crypto.cryptoki jdk.crypto.ec jdk.crypto.mscapi
Building Individual Module Phases
The build process for each module is divided into separate phases. Not all modules need all phases. Which are needed depends on what kind of source code and other artifact the module consists of. The phases are:
diff --git a/doc/building.md b/doc/building.md
index 4eb8abee2f6..850f6f07da2 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -109,19 +109,11 @@ one of the limiting factors for build performance.
At a minimum, a machine with 2-4 cores is advisable, as well as 2-4 GB of RAM.
(The more cores to use, the more memory you need.) At least 6 GB of free disk
-space is required (8 GB minimum for building on Solaris).
+space is required.
Even for 32-bit builds, it is recommended to use a 64-bit build machine, and
instead create a 32-bit target using `--with-target-bits=32`.
-### Building on sparc
-
-At a minimum, a machine with 4 cores is advisable, as well as 4 GB of RAM. (The
-more cores to use, the more memory you need.) At least 8 GB of free disk space
-is required.
-
-Note: The sparc port is deprecated.
-
### Building on aarch64
At a minimum, a machine with 8 cores is advisable, as well as 8 GB of RAM.
@@ -138,7 +130,7 @@ This is not recommended. Instead, see the section on [Cross-compiling](
## Operating System Requirements
-The mainline JDK project supports Linux, Solaris, macOS, AIX and Windows.
+The mainline JDK project supports Linux, macOS, AIX and Windows.
Support for other operating system, e.g. BSD, exists in separate "port"
projects.
@@ -153,11 +145,10 @@ time of writing.
Operating system Vendor/version used
----------------- -------------------------------------------------------
Linux Oracle Enterprise Linux 6.4 / 7.6
- Solaris Solaris 11.3 SRU 20
macOS Mac OS X 10.13 (High Sierra)
Windows Windows Server 2012 R2
-The double version numbers for Linux and Solaris are due to the hybrid model
+The double version numbers for Linux are due to the hybrid model
used at Oracle, where header files and external libraries from an older version
are used when building on a more modern version of the OS.
@@ -247,21 +238,6 @@ options.
Note that while it's possible to build on WSL, testing is still not fully
supported.
-### Solaris
-
-See `make/devkit/solaris11.1-package-list.txt` for a list of recommended
-packages to install when building on Solaris. The versions specified in this
-list is the versions used by the daily builds at Oracle, and is likely to work
-properly.
-
-Older versions of Solaris shipped a broken version of `objcopy`. At least
-version 2.21.1 is needed, which is provided by Solaris 11 Update 1. Objcopy is
-needed if you want to have external debug symbols. Please make sure you are
-using at least version 2.21.1 of objcopy, or that you disable external debug
-symbols.
-
-Note: The Solaris port is deprecated.
-
### macOS
Apple is using a quite aggressive scheme of pushing OS updates, and coupling
@@ -314,7 +290,6 @@ one-to-one correlation between target operating system and toolchain.
------------------ -------------------------
Linux gcc, clang
macOS Apple Xcode (using clang)
- Solaris Oracle Solaris Studio
AIX IBM XL C/C++
Windows Microsoft Visual Studio
@@ -329,7 +304,6 @@ issues.
------------------ -------------------------------------------------------
Linux gcc 9.2.0
macOS Apple Xcode 10.1 (using clang 10.0.0)
- Solaris Oracle Solaris Studio 12.6 (with compiler version 5.15)
Windows Microsoft Visual Studio 2019 update 16.5.3
All compilers are expected to be able to compile to the C99 language standard,
@@ -379,36 +353,6 @@ Build Environment](#problems-with-the-build-environment), and [Getting
Help](#getting-help) to find out if there are any recent, non-merged patches
available for this update.
-### Oracle Solaris Studio
-
-The minimum accepted version of the Solaris Studio compilers is 5.13
-(corresponding to Solaris Studio 12.4). Older versions will not be accepted by
-configure.
-
-The Solaris Studio installation should contain at least these packages:
-
- Package Version
- -------------------------------------------------- -------------
- developer/solarisstudio-124/backend 12.4-1.0.6.0
- developer/solarisstudio-124/c++ 12.4-1.0.10.0
- developer/solarisstudio-124/cc 12.4-1.0.4.0
- developer/solarisstudio-124/library/c++-libs 12.4-1.0.10.0
- developer/solarisstudio-124/library/math-libs 12.4-1.0.0.1
- developer/solarisstudio-124/library/studio-gccrt 12.4-1.0.0.1
- developer/solarisstudio-124/studio-common 12.4-1.0.0.1
- developer/solarisstudio-124/studio-ja 12.4-1.0.0.1
- developer/solarisstudio-124/studio-legal 12.4-1.0.0.1
- developer/solarisstudio-124/studio-zhCN 12.4-1.0.0.1
-
-Compiling with Solaris Studio can sometimes be finicky. This is the exact
-version used by Oracle, which worked correctly at the time of writing:
-```
-$ cc -V
-cc: Sun C 5.13 SunOS_i386 2014/10/20
-$ CC -V
-CC: Sun C++ 5.13 SunOS_i386 151846-10 2015/10/30
-```
-
### Microsoft Visual Studio
The minimum accepted version of Visual Studio is 2010. Older versions will not
@@ -494,7 +438,6 @@ rather than bundling the JDK's own copy.
libfreetype6-dev`.
* To install on an rpm-based Linux, try running `sudo yum install
freetype-devel`.
- * To install on Solaris, try running `pkg install system/library/freetype-2`.
Use `--with-freetype-include=` and `--with-freetype-lib=`
if `configure` does not automatically locate the platform FreeType files.
@@ -509,7 +452,6 @@ your operating system.
libcups2-dev`.
* To install on an rpm-based Linux, try running `sudo yum install
cups-devel`.
- * To install on Solaris, try running `pkg install print/cups`.
Use `--with-cups=` if `configure` does not properly locate your CUPS
files.
@@ -517,18 +459,12 @@ files.
### X11
Certain [X11](http://www.x.org/) libraries and include files are required on
-Linux and Solaris.
+Linux.
* To install on an apt-based Linux, try running `sudo apt-get install
libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev`.
* To install on an rpm-based Linux, try running `sudo yum install
libXtst-devel libXt-devel libXrender-devel libXrandr-devel libXi-devel`.
- * To install on Solaris, try running `pkg install x11/header/x11-protocols
- x11/library/libice x11/library/libpthread-stubs x11/library/libsm
- x11/library/libx11 x11/library/libxau x11/library/libxcb
- x11/library/libxdmcp x11/library/libxevie x11/library/libxext
- x11/library/libxrender x11/library/libxrandr x11/library/libxscrnsaver
- x11/library/libxtst x11/library/toolkit/libxt`.
Use `--with-x=` if `configure` does not properly locate your X11 files.
@@ -603,8 +539,6 @@ will present no issues, but if you have a very old `make`, or a non-GNU Make
If you want to override the default make found by `configure`, use the `MAKE`
configure variable, e.g. `configure MAKE=/opt/gnu/make`.
-On Solaris, it is common to call the GNU version of make by using `gmake`.
-
### GNU Bash
The JDK requires [GNU Bash](http://www.gnu.org/software/bash). No other shells
@@ -1460,12 +1394,6 @@ clean` and restart the build.
#### Out of Memory Errors
-On Solaris, you might get an error message like this:
-```
-Trouble writing out table to disk
-```
-To solve this, increase the amount of swap space on your build machine.
-
On Windows, you might get error messages like this:
```
fatal error - couldn't allocate heap
@@ -1604,8 +1532,7 @@ module depends on other modules (e.g. `java.base`), those modules will be built
first.
You can also specify a set of modules, just as you can always specify a set of
-make targets: `make jdk.crypto.cryptoki jdk.crypto.ec jdk.crypto.mscapi
-jdk.crypto.ucrypto`
+make targets: `make jdk.crypto.cryptoki jdk.crypto.ec jdk.crypto.mscapi`
#### Building Individual Module Phases
diff --git a/doc/testing.html b/doc/testing.html
index c4ad9e6c40c..ae38528722f 100644
--- a/doc/testing.html
+++ b/doc/testing.html
@@ -133,7 +133,7 @@ TEST FAILURE
JTReg keywords
JOBS
The test concurrency (-concurrency
).
-Defaults to TEST_JOBS (if set by --with-test-jobs=
), otherwise it defaults to JOBS, except for Hotspot, where the default is number of CPU cores/2 (for sparc, if more than 16 cpus, then number of CPU cores/5, otherwise number of CPU cores/4), but never more than memory size in GB/2.
+Defaults to TEST_JOBS (if set by --with-test-jobs=
), otherwise it defaults to JOBS, except for Hotspot, where the default is number of CPU cores/2, but never more than memory size in GB/2.
TIMEOUT_FACTOR
The timeout factor (-timeoutFactor
).
Defaults to 4.
diff --git a/doc/testing.md b/doc/testing.md
index 31d45d0a339..8a42ea92e69 100644
--- a/doc/testing.md
+++ b/doc/testing.md
@@ -261,9 +261,8 @@ file.
The test concurrency (`-concurrency`).
Defaults to TEST_JOBS (if set by `--with-test-jobs=`), otherwise it defaults to
-JOBS, except for Hotspot, where the default is *number of CPU cores/2* (for
-sparc, if more than 16 cpus, then *number of CPU cores/5*, otherwise *number of
-CPU cores/4*), but never more than *memory size in GB/2*.
+JOBS, except for Hotspot, where the default is *number of CPU cores/2*,
+but never more than *memory size in GB/2*.
#### TIMEOUT_FACTOR
The timeout factor (`-timeoutFactor`).
diff --git a/make/Bundles.gmk b/make/Bundles.gmk
index c411bfe212b..333936d10ec 100644
--- a/make/Bundles.gmk
+++ b/make/Bundles.gmk
@@ -101,7 +101,7 @@ define SetupBundleFileBody
# If no subdir is specified and only one BASE_DIR, tar.gz can be done
# directly from BASE_DIR.
$(CD) $$($1_BASE_DIRS) \
- && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
+ && ( $(TAR) cf - \
-$(TAR_INCLUDE_PARAM) $$($1_$$($1_BASE_DIRS)_LIST_FILE) \
$(TAR_IGNORE_EXIT_VALUE) ) \
| $(GZIP) > $$@
@@ -110,7 +110,7 @@ define SetupBundleFileBody
# If only one BASE_DIR, but with a SUBDIR set, tar.gz can use the
# transform option to create bundle directly from the BASE_DIR.
$(CD) $$($1_BASE_DIRS) \
- && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
+ && ( $(TAR) cf - \
-$(TAR_INCLUDE_PARAM) $$($1_$$($1_BASE_DIRS)_LIST_FILE) \
$$(if $$($1_SUBDIR), --transform 's|^|$$($1_SUBDIR)/|S') \
$(TAR_IGNORE_EXIT_VALUE) ) \
@@ -140,7 +140,7 @@ define SetupBundleFileBody
endif
ifeq ($$($1_TYPE), tar.gz)
$(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1 && \
- ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
+ ( $(TAR) cf - \
$$(if $$($1_SUBDIR), $$($1_SUBDIR), .) $(TAR_IGNORE_EXIT_VALUE) ) \
| $(GZIP) > $$@
else ifeq ($$($1_TYPE), zip)
diff --git a/make/CompileDemos.gmk b/make/CompileDemos.gmk
index 36c56ab6058..65105f14adf 100644
--- a/make/CompileDemos.gmk
+++ b/make/CompileDemos.gmk
@@ -240,15 +240,9 @@ $(SUPPORT_OUTPUTDIR)/demos/image/nbproject/%: $(DEMO_SHARE_SRC)/nbproject/%
$(call install-file)
$(CHMOD) -f ug+w $@
-ifeq ($(call isTargetOs, solaris), true)
- TARGETS += $(patsubst $(DEMO_SHARE_SRC)/nbproject/%, \
- $(SUPPORT_OUTPUTDIR)/demos/image/nbproject/%, \
- $(call FindFiles, $(DEMO_SHARE_SRC)/nbproject))
-else
- TARGETS += $(patsubst $(DEMO_SHARE_SRC)/nbproject/%, \
- $(SUPPORT_OUTPUTDIR)/demos/image/nbproject/%, \
- $(call FindFiles, $(DEMO_SHARE_SRC)/nbproject))
-endif
+TARGETS += $(patsubst $(DEMO_SHARE_SRC)/nbproject/%, \
+ $(SUPPORT_OUTPUTDIR)/demos/image/nbproject/%, \
+ $(call FindFiles, $(DEMO_SHARE_SRC)/nbproject))
################################################################################
diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk
index 85c2232ec7f..4da52baecdb 100644
--- a/make/CompileJavaModules.gmk
+++ b/make/CompileJavaModules.gmk
@@ -53,14 +53,7 @@ java.base_EXCLUDES += java/lang/doc-files
# data files and shouldn't go in the product
java.base_EXCLUDE_FILES += sun/text/resources/BreakIteratorRules.java
-ifeq ($(call isTargetOs, solaris), false)
- java.base_EXCLUDE_FILES += \
- SolarisLoginModule.java \
- SolarisSystem.java \
- #
-endif
-
-ifeq ($(call isTargetOs, solaris macosx aix), false)
+ifeq ($(call isTargetOs, macosx aix), false)
java.base_EXCLUDE_FILES += sun/nio/fs/PollingWatchService.java
endif
@@ -448,10 +441,8 @@ jdk.internal.vm.compiler_JAVAC_FLAGS += -parameters -XDstringConcat=inline \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=jdk.internal.vm.compiler \
- --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.sparc=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.meta=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.runtime=jdk.internal.vm.compiler \
- --add-exports jdk.internal.vm.ci/jdk.vm.ci.sparc=jdk.internal.vm.compiler \
#
jdk.internal.vm.compiler_EXCLUDES += \
@@ -461,7 +452,6 @@ jdk.internal.vm.compiler_EXCLUDES += \
org.graalvm.compiler.api.test \
org.graalvm.compiler.asm.aarch64.test \
org.graalvm.compiler.asm.amd64.test \
- org.graalvm.compiler.asm.sparc.test \
org.graalvm.compiler.asm.test \
org.graalvm.compiler.core.aarch64.test \
org.graalvm.compiler.core.amd64.test \
@@ -475,7 +465,6 @@ jdk.internal.vm.compiler_EXCLUDES += \
org.graalvm.compiler.hotspot.jdk15.test \
org.graalvm.compiler.hotspot.jdk9.test \
org.graalvm.compiler.hotspot.lir.test \
- org.graalvm.compiler.hotspot.sparc.test \
org.graalvm.compiler.hotspot.test \
org.graalvm.compiler.jtt \
org.graalvm.compiler.lir.jtt \
@@ -517,10 +506,8 @@ jdk.aot_JAVAC_FLAGS += -parameters -XDstringConcat=inline \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot=jdk.internal.vm.compiler,jdk.aot \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=jdk.internal.vm.compiler,jdk.aot \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=jdk.internal.vm.compiler,jdk.aot \
- --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.sparc=jdk.internal.vm.compiler,jdk.aot \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.meta=jdk.internal.vm.compiler,jdk.aot \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.runtime=jdk.internal.vm.compiler,jdk.aot \
- --add-exports jdk.internal.vm.ci/jdk.vm.ci.sparc=jdk.internal.vm.compiler,jdk.aot \
#
jdk.aot_EXCLUDES += \
diff --git a/make/RunTests.gmk b/make/RunTests.gmk
index ecabdbcb696..28da3d8f2ba 100644
--- a/make/RunTests.gmk
+++ b/make/RunTests.gmk
@@ -237,16 +237,6 @@ TEST_JOBS_FACTOR_MACHINE ?= 1
ifeq ($(TEST_JOBS), 0)
CORES_DIVIDER := 2
- ifeq ($(call isTargetCpuArch, sparc), true)
- # For smaller SPARC machines we see reasonable scaling of throughput up to
- # cpus/4 without affecting test reliability. On the bigger machines, cpus/4
- # causes intermittent timeouts.
- ifeq ($(shell $(EXPR) $(NUM_CORES) \> 16), 1)
- CORES_DIVIDER := 5
- else
- CORES_DIVIDER := 4
- endif
- endif
# For some big multi-core machines with low ulimit -u setting we hit the max
# threads/process limit. In such a setup the memory/cores-only-guided
# TEST_JOBS config is insufficient. From experience a concurrency setting of
@@ -843,12 +833,8 @@ define SetupRunJtregTestBody
# we may end up with a lot of JVM's
$1_JTREG_MAX_RAM_PERCENTAGE := $$(shell $$(EXPR) 25 / $$($1_JTREG_JOBS))
- # SPARC is in general slower per core so need to scale up timeouts a bit.
- ifeq ($(call isTargetCpuArch, sparc), true)
- JTREG_TIMEOUT_FACTOR ?= 8
- else
- JTREG_TIMEOUT_FACTOR ?= 4
- endif
+ JTREG_TIMEOUT_FACTOR ?= 4
+
JTREG_VERBOSE ?= fail,error,summary
JTREG_RETAIN ?= fail,error
JTREG_RUN_PROBLEM_LISTS ?= false
diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk
index 213131fbf63..3468ca4daf1 100644
--- a/make/RunTestsPrebuilt.gmk
+++ b/make/RunTestsPrebuilt.gmk
@@ -163,8 +163,6 @@ else
OPENJDK_TARGET_OS := linux
else ifeq ($(UNAME_OS), Darwin)
OPENJDK_TARGET_OS := macosx
- else ifeq ($(UNAME_OS), SunOS)
- OPENJDK_TARGET_OS := solaris
else
OPENJDK_TARGET_OS := $(UNAME_OS)
endif
@@ -174,38 +172,20 @@ endif
# Assume little endian unless otherwise specified
OPENJDK_TARGET_CPU_ENDIAN := little
-ifeq ($(OPENJDK_TARGET_OS), solaris)
- # On solaris, use uname -p
- UNAME_CPU := $(shell $(UNAME) -p)
- # Assume 64-bit platform
- OPENJDK_TARGET_CPU_BITS := 64
- ifeq ($(UNAME_CPU), i386)
- OPENJDK_TARGET_CPU := x86_64
- else ifeq ($(UNAME_CPU), sparc)
- OPENJDK_TARGET_CPU := sparcv9
- OPENJDK_TARGET_CPU_ENDIAN := big
- else
- OPENJDK_TARGET_CPU := $(UNAME_CPU)
- endif
+UNAME_CPU := $(shell $(UNAME) -m)
+ifeq ($(UNAME_CPU), i686)
+ OPENJDK_TARGET_CPU := x86
+ OPENJDK_TARGET_CPU_BITS := 32
else
- # ... all others use uname -m
- UNAME_CPU := $(shell $(UNAME) -m)
- ifeq ($(UNAME_CPU), i686)
- OPENJDK_TARGET_CPU := x86
- OPENJDK_TARGET_CPU_BITS := 32
- else
- # Assume all others are 64-bit. We use the same CPU name as uname for
- # at least x86_64 and aarch64.
- OPENJDK_TARGET_CPU := $(UNAME_CPU)
- OPENJDK_TARGET_CPU_BITS := 64
- endif
+ # Assume all others are 64-bit. We use the same CPU name as uname for
+ # at least x86_64 and aarch64.
+ OPENJDK_TARGET_CPU := $(UNAME_CPU)
+ OPENJDK_TARGET_CPU_BITS := 64
endif
OPENJDK_TARGET_CPU_ARCH := $(OPENJDK_TARGET_CPU)
ifeq ($(OPENJDK_TARGET_CPU), x86_64)
OPENJDK_TARGET_CPU_ARCH := x86
-else ifeq ($(OPENJDK_TARGET_CPU), sparcv9)
- OPENJDK_TARGET_CPU_ARCH := sparc
endif
ifeq ($(OPENJDK_TARGET_OS), windows)
@@ -229,11 +209,6 @@ ifeq ($(OPENJDK_TARGET_OS), linux)
else ifeq ($(OPENJDK_TARGET_OS), macosx)
NUM_CORES := $(shell /usr/sbin/sysctl -n hw.ncpu)
MEMORY_SIZE := $(shell $(EXPR) `/usr/sbin/sysctl -n hw.memsize` / 1024 / 1024)
-else ifeq ($(OPENJDK_TARGET_OS), solaris)
- NUM_CORES := $(shell /usr/sbin/psrinfo -v | $(GREP) -c on-line)
- MEMORY_SIZE := $(shell \
- /usr/sbin/prtconf 2> /dev/null | $(GREP) "^Memory [Ss]ize" | $(AWK) '{print $$3}' \
- )
else ifeq ($(OPENJDK_TARGET_OS), windows)
NUM_CORES := $(NUMBER_OF_PROCESSORS)
MEMORY_SIZE := $(shell \
@@ -265,11 +240,6 @@ ifneq ($(DEVKIT_HOME), )
LD_JAOTC := $(DEVKIT_HOME)/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
LIBRARY_PREFIX := lib
SHARED_LIBRARY_SUFFIX := .dylib
- else ifeq ($(OPENJDK_TARGET_OS), solaris)
- # Prefer system linker for AOT on Solaris.
- LD_JAOTC := ld
- LIBRARY_PREFIX := lib
- SHARED_LIBRARY_SUFFIX := .so
endif
else
LD := ld
diff --git a/make/RunTestsPrebuiltSpec.gmk b/make/RunTestsPrebuiltSpec.gmk
index 6fe80cffcec..33953c2b7d9 100644
--- a/make/RunTestsPrebuiltSpec.gmk
+++ b/make/RunTestsPrebuiltSpec.gmk
@@ -178,16 +178,6 @@ FILE := file
HG := hg
ULIMIT := ulimit
-# On Solaris gnu versions of some tools are required.
-ifeq ($(OPENJDK_BUILD_OS), solaris)
- AWK := gawk
- GREP := ggrep
- EGREP := ggrep -E
- FGREP := grep -F
- SED := gsed
- TAR := gtar
-endif
-
ifeq ($(OPENJDK_BUILD_OS), windows)
CYGPATH := cygpath
endif
diff --git a/make/ZipSecurity.gmk b/make/ZipSecurity.gmk
index 5a90890945d..f7435f05efe 100644
--- a/make/ZipSecurity.gmk
+++ b/make/ZipSecurity.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,6 @@ $(eval $(call SetupZipArchive,BUILD_SEC_BIN_ZIP, \
modules/jdk.crypto.mscapi/sun/security/mscapi \
modules/jdk.crypto.cryptoki/sun/security/pkcs11 \
modules/jdk.crypto.cryptoki/sun/security/pkcs11/wrapper \
- modules/jdk.crypto.ucrypto/com/oracle/security/ucrypto \
modules/java.base/javax/net \
modules/java.base/javax/security/cert \
modules/java.base/com/sun/net/ssl \
diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4
index 7a0040f650e..01289305baf 100644
--- a/make/autoconf/basic_tools.m4
+++ b/make/autoconf/basic_tools.m4
@@ -270,23 +270,15 @@ AC_DEFUN([BASIC_CHECK_TAR],
TAR_TYPE="bsd"
elif test "x$($TAR -v | $GREP "bsdtar")" != "x"; then
TAR_TYPE="bsd"
- elif test "x$OPENJDK_BUILD_OS" = "xsolaris"; then
- TAR_TYPE="solaris"
elif test "x$OPENJDK_BUILD_OS" = "xaix"; then
TAR_TYPE="aix"
fi
AC_MSG_CHECKING([what type of tar was found])
AC_MSG_RESULT([$TAR_TYPE])
- TAR_CREATE_FILE_PARAM=""
-
if test "x$TAR_TYPE" = "xgnu"; then
TAR_INCLUDE_PARAM="T"
TAR_SUPPORTS_TRANSFORM="true"
- if test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
- # When using gnu tar for Solaris targets, need to use compatibility mode
- TAR_CREATE_EXTRA_PARAM="--format=ustar"
- fi
elif test "x$TAR_TYPE" = "aix"; then
# -L InputList of aix tar: name of file listing the files and directories
# that need to be archived or extracted
@@ -297,7 +289,6 @@ AC_DEFUN([BASIC_CHECK_TAR],
TAR_SUPPORTS_TRANSFORM="false"
fi
AC_SUBST(TAR_TYPE)
- AC_SUBST(TAR_CREATE_EXTRA_PARAM)
AC_SUBST(TAR_INCLUDE_PARAM)
AC_SUBST(TAR_SUPPORTS_TRANSFORM)
])
@@ -359,7 +350,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
UTIL_PATH_PROGS(STAT, stat)
UTIL_PATH_PROGS(TIME, time)
UTIL_PATH_PROGS(FLOCK, flock)
- # Dtrace is usually found in /usr/sbin on Solaris, but that directory may not
+ # Dtrace is usually found in /usr/sbin, but that directory may not
# be in the user path.
UTIL_PATH_PROGS(DTRACE, dtrace, $PATH:/usr/sbin)
UTIL_PATH_PROGS(PATCH, [gpatch patch])
@@ -415,8 +406,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
fi
fi
UTIL_REQUIRE_PROGS(SETFILE, SetFile)
- elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
- UTIL_REQUIRE_PROGS(ELFEDIT, elfedit)
fi
if ! test "x$OPENJDK_TARGET_OS" = "xwindows"; then
UTIL_REQUIRE_BUILTIN_PROGS(ULIMIT, ulimit)
diff --git a/make/autoconf/build-aux/config.guess b/make/autoconf/build-aux/config.guess
index 86367a32e29..b650b5109d0 100644
--- a/make/autoconf/build-aux/config.guess
+++ b/make/autoconf/build-aux/config.guess
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -30,22 +30,6 @@
DIR=`dirname $0`
OUT=`. $DIR/autoconf-config.guess`
-# Test and fix solaris on x86_64
-echo $OUT | grep i386-pc-solaris > /dev/null 2> /dev/null
-if test $? = 0; then
- # isainfo -n returns either i386 or amd64
- REAL_CPU=`isainfo -n`
- OUT=$REAL_CPU`echo $OUT | sed -e 's/[^-]*//'`
-fi
-
-# Test and fix solaris on sparcv9
-echo $OUT | grep sparc-sun-solaris > /dev/null 2> /dev/null
-if test $? = 0; then
- # isainfo -n returns either sparc or sparcv9
- REAL_CPU=`isainfo -n`
- OUT=$REAL_CPU`echo $OUT | sed -e 's/[^-]*//'`
-fi
-
# Test and fix cygwin on x86_64
echo $OUT | grep 86-pc-cygwin > /dev/null 2> /dev/null
if test $? != 0; then
diff --git a/make/autoconf/build-performance.m4 b/make/autoconf/build-performance.m4
index ef47c9bb029..065b3027d6f 100644
--- a/make/autoconf/build-performance.m4
+++ b/make/autoconf/build-performance.m4
@@ -38,10 +38,6 @@ AC_DEFUN([BPERF_CHECK_CORES],
if test "$NUM_CORES" -ne "0"; then
FOUND_CORES=yes
fi
- elif test -x /usr/sbin/psrinfo; then
- # Looks like a Solaris system
- NUM_CORES=`/usr/sbin/psrinfo -v | grep -c on-line`
- FOUND_CORES=yes
elif test -x /usr/sbin/sysctl; then
# Looks like a MacOSX system
NUM_CORES=`/usr/sbin/sysctl -n hw.ncpu`
@@ -79,7 +75,7 @@ AC_DEFUN([BPERF_CHECK_MEMORY_SIZE],
MEMORY_SIZE=`expr $MEMORY_SIZE / 1024`
FOUND_MEM=yes
elif test -x /usr/sbin/prtconf; then
- # Looks like a Solaris or AIX system
+ # Looks like an AIX system
MEMORY_SIZE=`/usr/sbin/prtconf 2> /dev/null | grep "^Memory [[Ss]]ize" | awk '{ print [$]3 }'`
FOUND_MEM=yes
elif test -x /usr/sbin/sysctl; then
@@ -370,9 +366,6 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS],
if test "x$ICECC" != "x"; then
AC_MSG_RESULT([no, does not work effectively with icecc])
PRECOMPILED_HEADERS_AVAILABLE=false
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- AC_MSG_RESULT([no, does not work with Solaris Studio])
- PRECOMPILED_HEADERS_AVAILABLE=false
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
AC_MSG_RESULT([no, does not work with xlc])
PRECOMPILED_HEADERS_AVAILABLE=false
diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4
index 99e51891d82..da397aa8456 100644
--- a/make/autoconf/flags-cflags.m4
+++ b/make/autoconf/flags-cflags.m4
@@ -35,8 +35,6 @@
AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
[
if test "x$TOOLCHAIN_TYPE" = xgcc; then
- C_FLAG_REORDER=''
-
# Default works for linux, might work on other platforms as well.
SHARED_LIBRARY_FLAGS='-shared'
SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1'
@@ -45,8 +43,6 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=[$]1'
elif test "x$TOOLCHAIN_TYPE" = xclang; then
- C_FLAG_REORDER=''
-
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# Linking is different on MacOSX
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0"
@@ -71,16 +67,7 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
fi
fi
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- C_FLAG_REORDER='-xF'
- SHARED_LIBRARY_FLAGS="-G"
- SET_EXECUTABLE_ORIGIN='-R\$$ORIGIN[$]1'
- SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
- SET_SHARED_LIBRARY_NAME='-h [$]1'
- SET_SHARED_LIBRARY_MAPFILE='-M[$]1'
-
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- C_FLAG_REORDER=''
SHARED_LIBRARY_FLAGS="-qmkshrobj -bM:SRE -bnoentry"
SET_EXECUTABLE_ORIGIN=""
SET_SHARED_LIBRARY_ORIGIN=''
@@ -88,7 +75,6 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
SET_SHARED_LIBRARY_MAPFILE=''
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
- C_FLAG_REORDER=''
SHARED_LIBRARY_FLAGS="-dll"
SET_EXECUTABLE_ORIGIN=''
SET_SHARED_LIBRARY_ORIGIN=''
@@ -96,7 +82,6 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
SET_SHARED_LIBRARY_MAPFILE='-def:[$]1'
fi
- AC_SUBST(C_FLAG_REORDER)
AC_SUBST(SET_EXECUTABLE_ORIGIN)
AC_SUBST(SET_SHARED_LIBRARY_ORIGIN)
AC_SUBST(SET_SHARED_LIBRARY_NAME)
@@ -117,9 +102,6 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS],
elif test "x$TOOLCHAIN_TYPE" = xclang; then
CFLAGS_DEBUG_SYMBOLS="-g"
ASFLAGS_DEBUG_SYMBOLS="-g"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- # -g0 enables debug symbols without disabling inlining.
- CFLAGS_DEBUG_SYMBOLS="-g0 -xs"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
CFLAGS_DEBUG_SYMBOLS="-g1"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
@@ -154,17 +136,6 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
DISABLED_WARNINGS="4800"
;;
- solstudio)
- DISABLE_WARNING_PREFIX="-erroff="
- CFLAGS_WARNINGS_ARE_ERRORS="-errwarn=%all"
-
- WARNINGS_ENABLE_ALL_CFLAGS="-v -fd -xtransition"
- WARNINGS_ENABLE_ALL_CXXFLAGS="+w +w2"
-
- DISABLED_WARNINGS_C="E_OLD_STYLE_FUNC_DECL E_OLD_STYLE_FUNC_DEF E_SEMANTICS_OF_OP_CHG_IN_ANSI_C E_NO_REPLACEMENT_IN_STRING E_DECLARATION_IN_CODE"
- DISABLED_WARNINGS_CXX="inllargeuse inllargeint notused wemptydecl notemsource"
- ;;
-
gcc)
DISABLE_WARNING_PREFIX="-Wno-"
CFLAGS_WARNINGS_ARE_ERRORS="-Werror"
@@ -244,25 +215,7 @@ AC_DEFUN([FLAGS_SETUP_QUALITY_CHECKS],
AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
[
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- CC_HIGHEST="-fns -fsimple -fsingle -xbuiltin=%all -xdepend -xrestrict -xlibmil"
-
- C_O_FLAG_HIGHEST_JVM="-xO4"
- C_O_FLAG_DEBUG_JVM=""
- C_O_FLAG_SIZE=""
- C_O_FLAG_DEBUG=""
- C_O_FLAG_NONE=""
- if test "x$OPENJDK_TARGET_CPU_ARCH" = "xx86"; then
- C_O_FLAG_HIGHEST="-xO4 -Wu,-O4~yz $CC_HIGHEST"
- C_O_FLAG_HI="-xO4 -Wu,-O4~yz"
- C_O_FLAG_NORM="-xO2 -Wu,-O2~yz"
- elif test "x$OPENJDK_TARGET_CPU_ARCH" = "xsparc"; then
- C_O_FLAG_HIGHEST="-xO4 -Wc,-Qrm-s -Wc,-Qiselect-T0 \
- -xprefetch=auto,explicit $CC_HIGHEST"
- C_O_FLAG_HI="-xO4 -Wc,-Qrm-s -Wc,-Qiselect-T0"
- C_O_FLAG_NORM="-xO2 -Wc,-Qrm-s -Wc,-Qiselect-T0"
- fi
- elif test "x$TOOLCHAIN_TYPE" = xgcc; then
+ if test "x$TOOLCHAIN_TYPE" = xgcc; then
C_O_FLAG_HIGHEST_JVM="-O3"
C_O_FLAG_HIGHEST="-O3"
C_O_FLAG_HI="-O3"
@@ -334,11 +287,6 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
CXX_O_FLAG_NONE="$C_O_FLAG_NONE"
CXX_O_FLAG_SIZE="$C_O_FLAG_SIZE"
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- # In solstudio, also add this to C (but not C++) flags...
- C_O_FLAG_HIGHEST="$C_O_FLAG_HIGHEST -xalias_level=basic"
- fi
-
# Adjust optimization flags according to debug level.
case $DEBUG_LEVEL in
release )
@@ -431,9 +379,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
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"
- elif test "x$OPENJDK_TARGET_OS" = xsolaris; then
- CFLAGS_OS_DEF_JVM="-DSOLARIS"
- CFLAGS_OS_DEF_JDK="-D__solaris__"
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"
@@ -469,9 +414,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
# Setup debug/release defines
if test "x$DEBUG_LEVEL" = xrelease; then
DEBUG_CFLAGS_JDK="-DNDEBUG"
- if test "x$OPENJDK_TARGET_OS" = xsolaris; then
- DEBUG_CFLAGS_JDK="$DEBUG_CFLAGS_JDK -DTRIMMED"
- fi
else
DEBUG_CFLAGS_JDK="-DDEBUG"
@@ -494,10 +436,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
ALWAYS_DEFINES_JVM="-D_GNU_SOURCE -D_REENTRANT"
elif test "x$TOOLCHAIN_TYPE" = xclang; then
ALWAYS_DEFINES_JVM="-D_GNU_SOURCE"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- ALWAYS_DEFINES_JVM="-DSPARC_WORKS -D_Crun_inline_placement"
- ALWAYS_DEFINES_JDK="-DTRACING -DMACRO_MEMSYS_OPS -DBREAKPTS"
- ALWAYS_DEFINES_JDK_CXXONLY="-DCC_NOEX"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
ALWAYS_DEFINES_JVM="-D_REENTRANT"
ALWAYS_DEFINES_JDK="-D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE -DSTDC"
@@ -554,20 +492,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
TOOLCHAIN_CFLAGS_JDK="-pipe"
TOOLCHAIN_CFLAGS_JDK_CONLY="-fno-strict-aliasing" # technically NOT for CXX
fi
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- TOOLCHAIN_FLAGS="-errtags -errfmt"
- TOOLCHAIN_CFLAGS="-errshort=tags"
-
- TOOLCHAIN_CFLAGS_JDK="-mt $TOOLCHAIN_FLAGS"
- TOOLCHAIN_CFLAGS_JDK_CONLY="-W0,-noglobal $TOOLCHAIN_CFLAGS" # C only
- TOOLCHAIN_CFLAGS_JDK_CXXONLY="-features=no%except -norunpath -xnolib" # CXX only
- TOOLCHAIN_CFLAGS_JVM="-template=no%extdef -features=no%split_init \
- -library=stlport4 -mt -features=no%except $TOOLCHAIN_FLAGS"
- if test "x$DEBUG_LEVEL" = xslowdebug; then
- # Previously -g was used instead of -g0 for slowdebug; this is equivalent
- # to setting +d.
- TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM +d"
- fi
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
# Suggested additions: -qsrcmsg to get improved error reporting
@@ -588,11 +512,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang || test "x$TOOLCHAIN_TYPE" = xxlc; then
# Explicitly set C99. clang and xlclang support the same flag.
LANGSTD_CFLAGS="-std=c99"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- # We can't turn on -std=c99 without breaking compilation of the splashscreen/png
- # utilities. But we can enable c99 as below (previously achieved by using -Xa).
- # It is the no_lib that makes the difference.
- LANGSTD_CFLAGS="-xc99=all,no_lib"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
# MSVC doesn't support C99/C11 explicitly, unless you compile as C++:
# LANGSTD_CFLAGS="-TP"
@@ -613,11 +532,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
elif test "x$TOOLCHAIN_TYPE" = xclang; then
WARNING_CFLAGS="$WARNINGS_ENABLE_ALL"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- WARNING_CFLAGS_JDK_CONLY="$WARNINGS_ENABLE_ALL_CFLAGS"
- WARNING_CFLAGS_JDK_CXXONLY="$WARNINGS_ENABLE_ALL_CXXFLAGS"
- WARNING_CFLAGS_JVM="$WARNINGS_ENABLE_ALL_CXXFLAGS"
-
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
WARNING_CFLAGS="$WARNINGS_ENABLE_ALL"
@@ -642,8 +556,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
PICFLAG="-fPIC"
PIEFLAG="-fPIE"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- PICFLAG="-KPIC"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
# '-qpic' defaults to 'qpic=small'. This means that the compiler generates only
# one instruction for accessing the TOC. If the TOC grows larger than 64K, the linker
@@ -725,21 +637,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
# Setup endianness
if test "x$FLAGS_CPU_ENDIAN" = xlittle; then
$1_DEFINES_CPU_JVM="-DVM_LITTLE_ENDIAN"
- fi
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- # The macro _LITTLE_ENDIAN needs to be defined the same to avoid the
- # Sun C compiler warning message: warning: macro redefined: _LITTLE_ENDIAN
- if test "x$FLAGS_CPU_ENDIAN" = xlittle; then
- $1_DEFINES_CPU_JDK="-D_LITTLE_ENDIAN="
- else
- $1_DEFINES_CPU_JDK="-D_BIG_ENDIAN="
- fi
+ $1_DEFINES_CPU_JDK="-D_LITTLE_ENDIAN"
else
- if test "x$FLAGS_CPU_ENDIAN" = xlittle; then
- $1_DEFINES_CPU_JDK="-D_LITTLE_ENDIAN"
- else
- $1_DEFINES_CPU_JDK="-D_BIG_ENDIAN"
- fi
+ $1_DEFINES_CPU_JDK="-D_BIG_ENDIAN"
fi
# setup CPU bit size
@@ -752,19 +652,14 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
if test "x$FLAGS_OS" = xlinux || test "x$FLAGS_OS" = xmacosx; then
$1_DEFINES_CPU_JDK="${$1_DEFINES_CPU_JDK} -D_LP64=1"
fi
- if test "x$FLAGS_OS" != xsolaris && test "x$FLAGS_OS" != xaix; then
- # Solaris does not have _LP64=1 in the old build.
+ if test "x$FLAGS_OS" != xaix; then
# xlc on AIX defines _LP64=1 by default and issues a warning if we redefine it.
$1_DEFINES_CPU_JVM="${$1_DEFINES_CPU_JVM} -D_LP64=1"
fi
fi
# toolchain dependend, per-cpu
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- if test "x$FLAGS_CPU_ARCH" = xx86; then
- $1_DEFINES_CPU_JDK="${$1_DEFINES_CPU_JDK} -DcpuIntel -Di586 -D$FLAGS_CPU_LEGACY_LIB"
- fi
- elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
+ if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
if test "x$FLAGS_CPU" = xx86_64; then
$1_DEFINES_CPU_JDK="${$1_DEFINES_CPU_JDK} -D_AMD64_ -Damd64"
else
@@ -825,15 +720,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
fi
fi
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- if test "x$FLAGS_CPU" = xx86_64; then
- # NOTE: -xregs=no%frameptr is supposed to be default on x64
- $1_CFLAGS_CPU_JDK="-xregs=no%frameptr"
- elif test "x$FLAGS_CPU" = xsparcv9; then
- $1_CFLAGS_CPU_JVM="-xarch=sparc"
- $1_CFLAGS_CPU_JDK_LIBONLY="-xregs=no%appl"
- fi
-
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
if test "x$FLAGS_CPU" = xppc64; then
$1_CFLAGS_CPU_JVM="-qarch=ppc64"
@@ -955,27 +841,3 @@ AC_DEFUN([FLAGS_SETUP_GCC6_COMPILER_FLAGS],
PREFIX: $2, IF_FALSE: [NO_LIFETIME_DSE_CFLAG=""])
$1_GCC6_CFLAGS="${NO_DELETE_NULL_POINTER_CHECKS_CFLAG} ${NO_LIFETIME_DSE_CFLAG}"
])
-
-# Documentation on common flags used for solstudio in HIGHEST.
-#
-# WARNING: Use of OPTIMIZATION_LEVEL=HIGHEST in your Makefile needs to be
-# done with care, there are some assumptions below that need to
-# be understood about the use of pointers, and IEEE behavior.
-#
-# -fns: Use non-standard floating point mode (not IEEE 754)
-# -fsimple: Do some simplification of floating point arithmetic (not IEEE 754)
-# -fsingle: Use single precision floating point with 'float'
-# -xalias_level=basic: Assume memory references via basic pointer types do not alias
-# (Source with excessing pointer casting and data access with mixed
-# pointer types are not recommended)
-# -xbuiltin=%all: Use intrinsic or inline versions for math/std functions
-# (If you expect perfect errno behavior, do not use this)
-# -xdepend: Loop data dependency optimizations (need -xO3 or higher)
-# -xrestrict: Pointer parameters to functions do not overlap
-# (Similar to -xalias_level=basic usage, but less obvious sometimes.
-# If you pass in multiple pointers to the same data, do not use this)
-# -xlibmil: Inline some library routines
-# (If you expect perfect errno behavior, do not use this)
-# -xlibmopt: Use optimized math routines (CURRENTLY DISABLED)
-# (If you expect perfect errno behavior, do not use this)
-# Can cause undefined external on Solaris 8 X86 on __sincos, removing for now
diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4
index fc2529d0c26..a7c0f2fe799 100644
--- a/make/autoconf/flags-ldflags.m4
+++ b/make/autoconf/flags-ldflags.m4
@@ -88,14 +88,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \
-fPIC"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- BASIC_LDFLAGS="-Wl,-z,defs"
- BASIC_LDFLAGS_ONLYCXX="-norunpath"
- BASIC_LDFLAGS_ONLYCXX_JDK_ONLY="-xnolib"
-
- BASIC_LDFLAGS_JDK_ONLY="-ztext"
- BASIC_LDFLAGS_JVM_ONLY="-library=%none -mt -z noversion"
-
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
BASIC_LDFLAGS="-b64 -brtl -bnorwexec -bnolibpath -bexpall -bernotok -btextpsize:64K \
-bdatapsize:64K -bstackpsize:64K"
@@ -141,14 +133,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
fi
fi
- # Setup warning flags
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- LDFLAGS_WARNINGS_ARE_ERRORS="-Wl,-z,fatal-warnings"
- else
- LDFLAGS_WARNINGS_ARE_ERRORS=""
- fi
- AC_SUBST(LDFLAGS_WARNINGS_ARE_ERRORS)
-
# Setup LDFLAGS for linking executables
if test "x$TOOLCHAIN_TYPE" = xgcc; then
EXECUTABLE_LDFLAGS="$EXECUTABLE_LDFLAGS -Wl,--allow-shlib-undefined"
@@ -188,11 +172,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP],
$1_CPU_LDFLAGS="$ARM_ARCH_TYPE_FLAGS $ARM_FLOAT_TYPE_FLAGS"
fi
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- if test "x${OPENJDK_$1_CPU}" = "xsparcv9"; then
- $1_CPU_LDFLAGS_JVM_ONLY="-xarch=sparc"
- fi
-
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
if test "x${OPENJDK_$1_CPU}" = "xx86"; then
$1_CPU_LDFLAGS="-safeseh"
diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4
index 7280b500b96..a27bde453c8 100644
--- a/make/autoconf/flags-other.m4
+++ b/make/autoconf/flags-other.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -47,12 +47,10 @@ AC_DEFUN([FLAGS_SETUP_STRIPFLAGS],
[
## Setup strip.
# FIXME: should this really be per platform, or should it be per toolchain type?
- # strip is not provided by clang or solstudio; so guessing platform makes most sense.
+ # strip is not provided by clang; so guessing platform makes most sense.
# FIXME: we should really only export STRIPFLAGS from here, not POST_STRIP_CMD.
if test "x$OPENJDK_TARGET_OS" = xlinux; then
STRIPFLAGS="-g"
- elif test "x$OPENJDK_TARGET_OS" = xsolaris; then
- STRIPFLAGS="-x"
elif test "x$OPENJDK_TARGET_OS" = xmacosx; then
STRIPFLAGS="-S"
elif test "x$OPENJDK_TARGET_OS" = xaix; then
diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4
index 582cd65d0df..a7f959ff9ef 100644
--- a/make/autoconf/flags.m4
+++ b/make/autoconf/flags.m4
@@ -205,27 +205,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_USER_SUPPLIED_FLAGS],
AC_DEFUN([FLAGS_SETUP_SYSROOT_FLAGS],
[
if test "x[$]$1SYSROOT" != "x"; then
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- if test "x$OPENJDK_TARGET_OS" = xsolaris; then
- # Solaris Studio does not have a concept of sysroot. Instead we must
- # make sure the default include and lib dirs are appended to each
- # compile and link command line. Must also add -I-xbuiltin to enable
- # inlining of system functions and intrinsics.
- $1SYSROOT_CFLAGS="-I-xbuiltin -I[$]$1SYSROOT/usr/include"
- $1SYSROOT_LDFLAGS="-L[$]$1SYSROOT/usr/lib$OPENJDK_TARGET_CPU_ISADIR \
- -L[$]$1SYSROOT/lib$OPENJDK_TARGET_CPU_ISADIR"
- # If the devkit contains the ld linker, make sure we use it.
- AC_PATH_PROG(SOLARIS_LD, ld, , $DEVKIT_TOOLCHAIN_PATH:$DEVKIT_EXTRA_PATH)
- # Make sure this ld is runnable.
- if test -f "$SOLARIS_LD"; then
- if "$SOLARIS_LD" -V > /dev/null 2> /dev/null; then
- $1SYSROOT_LDFLAGS="[$]$1SYSROOT_LDFLAGS -Yl,$(dirname $SOLARIS_LD)"
- else
- AC_MSG_WARN([Could not run $SOLARIS_LD found in devkit, reverting to system ld])
- fi
- fi
- fi
- elif test "x$TOOLCHAIN_TYPE" = xgcc; then
+ if test "x$TOOLCHAIN_TYPE" = xgcc; then
$1SYSROOT_CFLAGS="--sysroot=[$]$1SYSROOT"
$1SYSROOT_LDFLAGS="--sysroot=[$]$1SYSROOT"
elif test "x$TOOLCHAIN_TYPE" = xclang; then
@@ -255,17 +235,14 @@ AC_DEFUN_ONCE([FLAGS_PRE_TOOLCHAIN],
# The sysroot flags are needed for configure to be able to run the compilers
FLAGS_SETUP_SYSROOT_FLAGS
- # For solstudio and xlc, the word size flag is required for correct behavior.
+ # For xlc, the word size flag is required for correct behavior.
# For clang/gcc, the flag is only strictly required for reduced builds, but
- # set it always where possible (x86, sparc and ppc).
+ # set it always where possible (x86 and ppc).
if test "x$TOOLCHAIN_TYPE" = xxlc; then
MACHINE_FLAG="-q${OPENJDK_TARGET_CPU_BITS}"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- MACHINE_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
elif test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
if test "x$OPENJDK_TARGET_CPU_ARCH" = xx86 &&
test "x$OPENJDK_TARGET_CPU" != xx32 ||
- test "x$OPENJDK_TARGET_CPU_ARCH" = xsparc ||
test "x$OPENJDK_TARGET_CPU_ARCH" = xppc; then
MACHINE_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
fi
@@ -318,11 +295,6 @@ AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL],
COMPILER_COMMAND_FILE_FLAG="@"
COMPILER_BINDCMD_FILE_FLAG=""
- # The solstudio linker does not support @-files.
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- COMPILER_COMMAND_FILE_FLAG=
- fi
-
# Check if @file is supported by gcc
if test "x$TOOLCHAIN_TYPE" = xgcc; then
AC_MSG_CHECKING([if @file is supported by gcc])
@@ -376,8 +348,6 @@ AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL],
C_FLAG_DEPS="-MMD -MF"
elif test "x$TOOLCHAIN_TYPE" = xclang; then
C_FLAG_DEPS="-MMD -MF"
- elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- C_FLAG_DEPS="-xMMD -xMF"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
C_FLAG_DEPS="-qmakedep=gcc -MF"
fi
diff --git a/make/autoconf/hotspot.m4 b/make/autoconf/hotspot.m4
index 0e4f4c283f6..f4dd27126d1 100644
--- a/make/autoconf/hotspot.m4
+++ b/make/autoconf/hotspot.m4
@@ -126,18 +126,6 @@ AC_DEFUN_ONCE([HOTSPOT_ENABLE_DISABLE_GTEST],
GTEST_AVAILABLE=false
fi
- # On solaris, we also must have the libstlport.so.1 library, setup in
- # LIB_SETUP_LIBRARIES.
- if test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
- AC_MSG_CHECKING([if the libstlport.so.1 library is present])
- if test "x$STLPORT_LIB" != "x"; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no, cannot build gtest])
- GTEST_AVAILABLE=false
- fi
- fi
-
UTIL_ARG_ENABLE(NAME: hotspot-gtest, DEFAULT: auto,
RESULT: BUILD_GTEST, AVAILABLE: $GTEST_AVAILABLE,
DEFAULT_DESC: [enabled if possible to build],
diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4
index 62cd17234df..7ebda1de525 100644
--- a/make/autoconf/jdk-options.m4
+++ b/make/autoconf/jdk-options.m4
@@ -291,7 +291,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
ZIP_EXTERNAL_DEBUG_SYMBOLS=false
elif test "x$with_native_debug_symbols" = xexternal; then
- if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
+ if test "x$OPENJDK_TARGET_OS" = xlinux; then
if test "x$OBJCOPY" = x; then
# enabling of enable-debug-symbols and can't find objcopy
# this is an error
@@ -304,7 +304,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
ZIP_EXTERNAL_DEBUG_SYMBOLS=false
elif test "x$with_native_debug_symbols" = xzipped; then
- if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
+ if test "x$OPENJDK_TARGET_OS" = xlinux; then
if test "x$OBJCOPY" = x; then
# enabling of enable-debug-symbols and can't find objcopy
# this is an error
diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4
index 2567034f9f7..8ec76f669f7 100644
--- a/make/autoconf/jvm-features.m4
+++ b/make/autoconf/jvm-features.m4
@@ -320,8 +320,7 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_JFR],
[
JVM_FEATURES_CHECK_AVAILABILITY(jfr, [
AC_MSG_CHECKING([if platform is supported by JFR])
- if test "x$OPENJDK_TARGET_OS" = xaix || \
- test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = "xlinux-sparcv9"; then
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU])
AVAILABLE=false
else
@@ -447,10 +446,6 @@ AC_DEFUN_ONCE([JVM_FEATURES_PREPARE_PLATFORM],
if test "x$OPENJDK_TARGET_OS" = xaix; then
JVM_FEATURES_PLATFORM_FILTER="$JVM_FEATURES_PLATFORM_FILTER jfr"
fi
-
- if test "x$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU" = "xlinux-sparcv9"; then
- JVM_FEATURES_PLATFORM_FILTER="$JVM_FEATURES_PLATFORM_FILTER jfr"
- fi
])
###############################################################################
diff --git a/make/autoconf/lib-freetype.m4 b/make/autoconf/lib-freetype.m4
index a870a89fba3..6bfc0ae6f15 100644
--- a/make/autoconf/lib-freetype.m4
+++ b/make/autoconf/lib-freetype.m4
@@ -53,13 +53,6 @@ AC_DEFUN([LIB_CHECK_POTENTIAL_FREETYPE],
if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then
AC_MSG_NOTICE([Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location.])
FOUND_FREETYPE=no
- else
- if test "x$OPENJDK_TARGET_OS" = "xsolaris" \
- && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then
- # Found lib in isa dir, use that instead.
- POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR"
- AC_MSG_NOTICE([Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead])
- fi
fi
fi
@@ -92,11 +85,11 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
# This setup is to verify access to system installed freetype header and
# libraries. On Windows and MacOS this does not apply and using these options
- # will report an error. On other platforms (Linux, Solaris), they will
- # default to using the system libraries. If they are found automatically,
- # nothing need be done. If they are not found, the configure
- # "--with-freetype-*" options may be used to fix that. If the preference is
- # to bundle on these platforms then use --with-freetype=bundled.
+ # will report an error. On other platforms they will default to using the
+ # system libraries. If they are found automatically, nothing need be done.
+ # If they are not found, the configure "--with-freetype-*" options may be
+ # used to fix that. If the preference is to bundle on these platforms then
+ # use --with-freetype=bundled.
FREETYPE_BASE_NAME=freetype
FREETYPE_CFLAGS=
@@ -167,15 +160,6 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
if test "x$PKG_CONFIG" != "x" ; then
PKG_CHECK_MODULES(FREETYPE, freetype2, [FOUND_FREETYPE=yes], [FOUND_FREETYPE=no])
if test "x$FOUND_FREETYPE" = "xyes" ; then
- # On solaris, pkg_check adds -lz to freetype libs, which isn't
- # necessary for us.
- FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'`
- # 64-bit libs for Solaris x86 are installed in the amd64
- # subdirectory, change lib to lib/amd64
- if test "x$OPENJDK_TARGET_OS" = "xsolaris" && \
- test "x$OPENJDK_TARGET_CPU" = "xx86_64" ; then
- FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'`
- fi
AC_MSG_CHECKING([for freetype])
AC_MSG_RESULT([yes (using pkg-config)])
fi
diff --git a/make/autoconf/lib-std.m4 b/make/autoconf/lib-std.m4
index cac99f00013..c6eac5bde66 100644
--- a/make/autoconf/lib-std.m4
+++ b/make/autoconf/lib-std.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -77,14 +77,6 @@ AC_DEFUN_ONCE([LIB_SETUP_STD_LIBS],
fi
fi
- # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so)
- if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then
- LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1"
- fi
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- LIBCXX_JVM="-lCrun"
- fi
-
AC_SUBST(LIBCXX)
# Setup Windows runtime dlls
diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4
index 7883698bdd5..f0f96f39c3e 100644
--- a/make/autoconf/lib-x11.m4
+++ b/make/autoconf/lib-x11.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -88,13 +88,6 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
AC_MSG_ERROR([Could not find X11 libraries. $HELP_MSG])
fi
- if test "x$OPENJDK_TARGET_OS" = xsolaris; then
- OPENWIN_HOME="/usr/openwin"
- X_CFLAGS="-I$SYSROOT$OPENWIN_HOME/include -I$SYSROOT$OPENWIN_HOME/include/X11/extensions"
- X_LIBS="-L$SYSROOT$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR \
- -R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR"
- fi
-
AC_LANG_PUSH(C)
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $SYSROOT_CFLAGS $X_CFLAGS"
@@ -122,16 +115,6 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
AC_MSG_ERROR([Could not find all X11 headers (shape.h Xrender.h Xrandr.h XTest.h Intrinsic.h). $HELP_MSG])
fi
- # If XLinearGradient isn't available in Xrender.h, signal that it needs to be
- # defined in libawt_xawt.
- AC_MSG_CHECKING([if XlinearGradient is defined in Xrender.h])
- AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM([[#include ]],
- [[XLinearGradient x;]])],
- [AC_MSG_RESULT([yes])],
- [AC_MSG_RESULT([no])
- X_CFLAGS="$X_CFLAGS -DSOLARIS10_NO_XRENDER_STRUCTS"])
-
CFLAGS="$OLD_CFLAGS"
AC_LANG_POP(C)
fi # NEEDS_LIB_X11
diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4
index 8618077d1bb..0002dba1604 100644
--- a/make/autoconf/libraries.m4
+++ b/make/autoconf/libraries.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -101,15 +101,8 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
LIB_SETUP_LIBFFI
LIB_SETUP_BUNDLED_LIBS
LIB_SETUP_MISC_LIBS
- LIB_SETUP_SOLARIS_STLPORT
LIB_TESTS_SETUP_GRAALUNIT
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- GLOBAL_LIBS="-lc"
- else
- GLOBAL_LIBS=""
- fi
-
BASIC_JDKLIB_LIBS=""
if test "x$TOOLCHAIN_TYPE" != xmicrosoft; then
BASIC_JDKLIB_LIBS="-ljava -ljvm"
@@ -119,15 +112,13 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
BASIC_JVM_LIBS="$LIBM"
# Dynamic loading library
- if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xaix; then
+ if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xaix; then
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBDL"
fi
# Threading library
if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xaix; then
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lpthread"
- elif test "x$OPENJDK_TARGET_OS" = xsolaris; then
- BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lthread"
fi
# perfstat lib
@@ -135,12 +126,6 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lperfstat"
fi
- if test "x$OPENJDK_TARGET_OS" = xsolaris; then
- BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -ldemangle -lnsl \
- -lrt -lkstat"
- BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM"
- fi
-
if test "x$OPENJDK_TARGET_OS" = xwindows; then
BASIC_JVM_LIBS="$BASIC_JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \
@@ -158,7 +143,6 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
AC_SUBST(JVM_LIBS)
AC_SUBST(OPENJDK_BUILD_JDKLIB_LIBS)
AC_SUBST(OPENJDK_BUILD_JVM_LIBS)
- AC_SUBST(GLOBAL_LIBS)
])
################################################################################
@@ -189,28 +173,3 @@ AC_DEFUN_ONCE([LIB_SETUP_MISC_LIBS],
LIBZIP_CAN_USE_MMAP=true
AC_SUBST(LIBZIP_CAN_USE_MMAP)
])
-
-################################################################################
-# libstlport.so.1 is needed for running gtest on Solaris. Find it to
-# redistribute it in the test image.
-################################################################################
-AC_DEFUN_ONCE([LIB_SETUP_SOLARIS_STLPORT],
-[
- if test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
- # Find the root of the Solaris Studio installation from the compiler path
- SOLARIS_STUDIO_DIR="$(dirname $CC)/.."
- STLPORT_LIB="$SOLARIS_STUDIO_DIR/lib/stlport4$OPENJDK_TARGET_CPU_ISADIR/libstlport.so.1"
- AC_MSG_CHECKING([for libstlport.so.1])
- if ! test -f "$STLPORT_LIB" && test "x$OPENJDK_TARGET_CPU_ISADIR" = "x/sparcv9"; then
- # SS12u3 has libstlport under 'stlport4/v9' instead of 'stlport4/sparcv9'
- STLPORT_LIB="$SOLARIS_STUDIO_DIR/lib/stlport4/v9/libstlport.so.1"
- fi
- if test -f "$STLPORT_LIB"; then
- AC_MSG_RESULT([yes, $STLPORT_LIB])
- UTIL_FIXUP_PATH([STLPORT_LIB])
- else
- AC_MSG_RESULT([no, not found at $STLPORT_LIB, cannot build Hotspot gtests])
- fi
- AC_SUBST(STLPORT_LIB)
- fi
-])
diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4
index ee5c75e7f36..c0f2446dbd7 100644
--- a/make/autoconf/platform.m4
+++ b/make/autoconf/platform.m4
@@ -162,6 +162,18 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_CPU],
VAR_CPU_BITS=64
VAR_CPU_ENDIAN=big
;;
+ sparc)
+ VAR_CPU=sparc
+ VAR_CPU_ARCH=sparc
+ VAR_CPU_BITS=32
+ VAR_CPU_ENDIAN=big
+ ;;
+ sparcv9|sparc64)
+ VAR_CPU=sparcv9
+ VAR_CPU_ARCH=sparc
+ VAR_CPU_BITS=64
+ VAR_CPU_ENDIAN=big
+ ;;
*)
AC_MSG_ERROR([unsupported cpu $1])
;;
@@ -178,10 +190,6 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_OS],
VAR_OS=linux
VAR_OS_TYPE=unix
;;
- *solaris*)
- VAR_OS=solaris
- VAR_OS_TYPE=unix
- ;;
*darwin*)
VAR_OS=macosx
VAR_OS_TYPE=unix
@@ -381,19 +389,6 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER],
fi
AC_SUBST(OPENJDK_$1_CPU_LEGACY_LIB)
- # OPENJDK_$1_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to
- # /amd64 or /sparcv9. This string is appended to some library paths, like this:
- # /usr/lib${OPENJDK_$1_CPU_ISADIR}/libexample.so
- OPENJDK_$1_CPU_ISADIR=""
- if test "x$OPENJDK_$1_OS" = xsolaris; then
- if test "x$OPENJDK_$1_CPU" = xx86_64; then
- OPENJDK_$1_CPU_ISADIR="/amd64"
- elif test "x$OPENJDK_$1_CPU" = xsparcv9; then
- OPENJDK_$1_CPU_ISADIR="/sparcv9"
- fi
- fi
- AC_SUBST(OPENJDK_$1_CPU_ISADIR)
-
# Setup OPENJDK_$1_CPU_OSARCH, which is used to set the os.arch Java system property
OPENJDK_$1_CPU_OSARCH="$OPENJDK_$1_CPU"
if test "x$OPENJDK_$1_OS" = xlinux && test "x$OPENJDK_$1_CPU" = xx86; then
@@ -510,9 +505,6 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER],
AC_DEFUN([PLATFORM_SET_RELEASE_FILE_OS_VALUES],
[
- if test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
- RELEASE_FILE_OS_NAME=SunOS
- fi
if test "x$OPENJDK_TARGET_OS" = "xlinux"; then
RELEASE_FILE_OS_NAME=Linux
fi
@@ -566,25 +558,9 @@ AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_AND_TARGET],
PLATFORM_SET_MODULE_TARGET_OS_VALUES
PLATFORM_SET_RELEASE_FILE_OS_VALUES
PLATFORM_SETUP_LEGACY_VARS
- PLATFORM_CHECK_DEPRECATION
-])
-AC_DEFUN([PLATFORM_CHECK_DEPRECATION],
-[
- UTIL_ARG_ENABLE(NAME: deprecated-ports, DEFAULT: false,
- RESULT: ENABLE_DEPRECATED_PORTS,
- DESC: [suppress the error when configuring for a deprecated port])
-
- if test "x$OPENJDK_TARGET_OS" = xsolaris || \
- (test "x$OPENJDK_TARGET_CPU_ARCH" = xsparc && \
- test "x$with_jvm_variants" != xzero); then
- if test "x$ENABLE_DEPRECATED_PORTS" = "xtrue"; then
- AC_MSG_WARN([The Solaris and SPARC ports are deprecated and may be removed in a future release.])
- else
- AC_MSG_ERROR(m4_normalize([The Solaris and SPARC ports are deprecated and may be removed in a
- future release. Use --enable-deprecated-ports=yes to suppress this error.]))
- fi
- fi
+ # Deprecated in JDK 15
+ UTIL_DEPRECATED_ARG_ENABLE(deprecated-ports)
])
AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_OS_VERSION],
diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in
index 10a1fc15931..98c5132832e 100644
--- a/make/autoconf/spec.gmk.in
+++ b/make/autoconf/spec.gmk.in
@@ -83,7 +83,6 @@ OPENJDK_TARGET_CPU_ENDIAN:=@OPENJDK_TARGET_CPU_ENDIAN@
COMPILE_TYPE:=@COMPILE_TYPE@
# Legacy support
-OPENJDK_TARGET_CPU_ISADIR:=@OPENJDK_TARGET_CPU_ISADIR@
OPENJDK_TARGET_CPU_LEGACY:=@OPENJDK_TARGET_CPU_LEGACY@
OPENJDK_TARGET_CPU_LEGACY_LIB:=@OPENJDK_TARGET_CPU_LEGACY_LIB@
OPENJDK_TARGET_CPU_OSARCH:=@OPENJDK_TARGET_CPU_OSARCH@
@@ -427,7 +426,7 @@ MACOSX_VERSION_MAX=@MACOSX_VERSION_MAX@
# The macosx code signing identity to use
MACOSX_CODESIGN_IDENTITY=@MACOSX_CODESIGN_IDENTITY@
-# Toolchain type: gcc, clang, solstudio, lxc, microsoft...
+# Toolchain type: gcc, clang, xlc, microsoft...
TOOLCHAIN_TYPE:=@TOOLCHAIN_TYPE@
TOOLCHAIN_VERSION := @TOOLCHAIN_VERSION@
CC_VERSION_NUMBER := @CC_VERSION_NUMBER@
@@ -470,7 +469,6 @@ CXX_FLAG_DEPS:=@CXX_FLAG_DEPS@
DISABLE_WARNING_PREFIX := @DISABLE_WARNING_PREFIX@
CFLAGS_WARNINGS_ARE_ERRORS:=@CFLAGS_WARNINGS_ARE_ERRORS@
-LDFLAGS_WARNINGS_ARE_ERRORS:=@LDFLAGS_WARNINGS_ARE_ERRORS@
DISABLED_WARNINGS := @DISABLED_WARNINGS@
DISABLED_WARNINGS_C := @DISABLED_WARNINGS_C@
DISABLED_WARNINGS_CXX := @DISABLED_WARNINGS_CXX@
@@ -524,7 +522,6 @@ SDKROOT:=@SDKROOT@
# LDFLAGS used to link the jdk native libraries (C-code)
LDFLAGS_JDKLIB:=@LDFLAGS_JDKLIB@
JDKLIB_LIBS:=@JDKLIB_LIBS@
-GLOBAL_LIBS:=@GLOBAL_LIBS@
# LDFLAGS used to link the jdk native launchers (C-code)
LDFLAGS_JDKEXE:=@LDFLAGS_JDKEXE@
@@ -574,10 +571,6 @@ INSTALL_NAME_TOOL:=@INSTALL_NAME_TOOL@
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
SET_SHARED_LIBRARY_MAPFILE=@SET_SHARED_LIBRARY_MAPFILE@
-# Options for C/CXX compiler to be used if linking is performed
-# using reorder file
-C_FLAG_REORDER:=@C_FLAG_REORDER@
-
#
# Options for generating debug symbols
COMPILE_WITH_DEBUG_SYMBOLS := @COMPILE_WITH_DEBUG_SYMBOLS@
@@ -746,7 +739,6 @@ WSLPATH:=@WSLPATH@
LDD:=@LDD@
OTOOL:=@OTOOL@
READELF:=@READELF@
-ELFEDIT:=@ELFEDIT@
EXPR:=@EXPR@
FILE:=@FILE@
DOT:=@DOT@
@@ -763,7 +755,6 @@ FIXPATH:=@FIXPATH@
ULIMIT:=@ULIMIT@
TAR_TYPE:=@TAR_TYPE@
-TAR_CREATE_EXTRA_PARAM:=@TAR_CREATE_EXTRA_PARAM@
TAR_INCLUDE_PARAM:=@TAR_INCLUDE_PARAM@
TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@
@@ -780,7 +771,6 @@ MSVCR_DLL:=@MSVCR_DLL@
VCRUNTIME_1_DLL:=@VCRUNTIME_1_DLL@
MSVCP_DLL:=@MSVCP_DLL@
UCRT_DLL_DIR:=@UCRT_DLL_DIR@
-STLPORT_LIB:=@STLPORT_LIB@
ENABLE_PANDOC:=@ENABLE_PANDOC@
PANDOC_MARKDOWN_FLAG:=@PANDOC_MARKDOWN_FLAG@
diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4
index 086b362ac00..a51757cb2ac 100644
--- a/make/autoconf/toolchain.m4
+++ b/make/autoconf/toolchain.m4
@@ -35,11 +35,10 @@
m4_include([toolchain_windows.m4])
# All valid toolchains, regardless of platform (used by help.m4)
-VALID_TOOLCHAINS_all="gcc clang solstudio xlc microsoft"
+VALID_TOOLCHAINS_all="gcc clang xlc microsoft"
# These toolchains are valid on different platforms
VALID_TOOLCHAINS_linux="gcc clang"
-VALID_TOOLCHAINS_solaris="solstudio"
VALID_TOOLCHAINS_macosx="gcc clang"
VALID_TOOLCHAINS_aix="xlc"
VALID_TOOLCHAINS_windows="microsoft"
@@ -48,14 +47,12 @@ VALID_TOOLCHAINS_windows="microsoft"
TOOLCHAIN_DESCRIPTION_clang="clang/LLVM"
TOOLCHAIN_DESCRIPTION_gcc="GNU Compiler Collection"
TOOLCHAIN_DESCRIPTION_microsoft="Microsoft Visual Studio"
-TOOLCHAIN_DESCRIPTION_solstudio="Oracle Solaris Studio"
TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++"
# Minimum supported versions, empty means unspecified
TOOLCHAIN_MINIMUM_VERSION_clang="3.2"
TOOLCHAIN_MINIMUM_VERSION_gcc="5.0"
TOOLCHAIN_MINIMUM_VERSION_microsoft="16.00.30319.01" # VS2010
-TOOLCHAIN_MINIMUM_VERSION_solstudio="5.13"
TOOLCHAIN_MINIMUM_VERSION_xlc=""
# Minimum supported linker versions, empty means unspecified
@@ -296,13 +293,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
TOOLCHAIN_CC_BINARY_clang="clang"
TOOLCHAIN_CC_BINARY_gcc="gcc"
TOOLCHAIN_CC_BINARY_microsoft="cl$EXE_SUFFIX"
- TOOLCHAIN_CC_BINARY_solstudio="cc"
TOOLCHAIN_CC_BINARY_xlc="xlclang"
TOOLCHAIN_CXX_BINARY_clang="clang++"
TOOLCHAIN_CXX_BINARY_gcc="g++"
TOOLCHAIN_CXX_BINARY_microsoft="cl$EXE_SUFFIX"
- TOOLCHAIN_CXX_BINARY_solstudio="CC"
TOOLCHAIN_CXX_BINARY_xlc="xlclang++"
# Use indirect variable referencing
@@ -409,28 +404,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
COMPILER=[$]$1
COMPILER_NAME=$2
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- # cc -V output typically looks like
- # cc: Sun C 5.12 Linux_i386 2011/11/16
- # or
- # cc: Studio 12.5 Sun C 5.14 SunOS_sparc 2016/05/31
- COMPILER_VERSION_OUTPUT=`$COMPILER -V 2>&1`
- # Check that this is likely to be the Solaris Studio cc.
- $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "^.* Sun $COMPILER_NAME" > /dev/null
- if test $? -ne 0; then
- ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
- AC_MSG_NOTICE([The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler.])
- AC_MSG_NOTICE([The result from running with -V was: "$COMPILER_VERSION_OUTPUT"])
- AC_MSG_NOTICE([The result from running with --version was: "$ALT_VERSION_OUTPUT"])
- AC_MSG_ERROR([A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir.])
- fi
- # Remove usage instructions (if present), and
- # collapse compiler output into a single line
- COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \
- $SED -e 's/ *@<:@Uu@:>@sage:.*//'`
- COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \
- $SED -e "s/^.*@<:@ ,\t@:>@$COMPILER_NAME@<:@ ,\t@:>@\(@<:@1-9@:>@\.@<:@0-9@:>@@<:@0-9@:>@*\).*/\1/"`
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
+ if test "x$TOOLCHAIN_TYPE" = xxlc; then
# xlc -qversion output typically looks like
# IBM XL C/C++ for AIX, V11.1 (5724-X13)
# Version: 11.01.0000.0015
@@ -615,19 +589,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION],
LINKER=[$]$1
LINKER_NAME="$2"
- if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
- # cc -Wl,-V output typically looks like
- # ld: Software Generation Utilities - Solaris Link Editors: 5.11-1.2329
-
- # solstudio cc requires us to have an existing file to pass as argument,
- # but it need not be a syntactically correct C file, so just use
- # ourself. :) The intermediate 'cat' is needed to stop ld from leaving
- # a lingering a.out (!).
- LINKER_VERSION_STRING=`$LD -Wl,-V $TOPDIR/configure 2>&1 | $CAT | $HEAD -n 1 | $SED -e 's/ld: //'`
- # Extract version number
- [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \
- $SED -e 's/.* \([0-9][0-9]*\.[0-9][0-9]*\)-\([0-9][0-9]*\.[0-9][0-9]*\)/\1.\2/'` ]
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
+ if test "x$TOOLCHAIN_TYPE" = xxlc; then
LINKER_VERSION_STRING="Unknown"
LINKER_VERSION_NUMBER="0.0"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
@@ -784,16 +746,8 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_CORE],
#
# Setup the assembler (AS)
#
- if test "x$OPENJDK_TARGET_OS" = xsolaris; then
- UTIL_PATH_PROGS(AS, as)
- UTIL_FIXUP_EXECUTABLE(AS)
- if test "x$AS" = x; then
- AC_MSG_ERROR([Solaris assembler (as) is required. Please install via "pkg install pkg:/developer/assembler".])
- fi
- else
- # FIXME: is this correct for microsoft?
- AS="$CC -c"
- fi
+ # FIXME: is this correct for microsoft?
+ AS="$CC -c"
AC_SUBST(AS)
#
@@ -842,15 +796,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA],
AC_CHECK_PROG([MSBUILD], [msbuild$EXE_SUFFIX], [msbuild$EXE_SUFFIX],,,)
fi
- if test "x$OPENJDK_TARGET_OS" = xsolaris; then
- UTIL_PATH_PROGS(STRIP, strip)
- UTIL_FIXUP_EXECUTABLE(STRIP)
- UTIL_PATH_PROGS(NM, nm)
- UTIL_FIXUP_EXECUTABLE(NM)
- UTIL_PATH_PROGS(GNM, gnm)
- UTIL_FIXUP_EXECUTABLE(GNM)
- elif test "x$OPENJDK_TARGET_OS" != xwindows; then
- # FIXME: we should unify this with the solaris case above.
+ if test "x$OPENJDK_TARGET_OS" != xwindows; then
UTIL_CHECK_TOOLS(STRIP, strip)
UTIL_FIXUP_EXECUTABLE(STRIP)
if test "x$TOOLCHAIN_TYPE" = xgcc; then
@@ -865,48 +811,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA],
# objcopy is used for moving debug symbols to separate files when
# full debug symbols are enabled.
- if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
+ if test "x$OPENJDK_TARGET_OS" = xlinux; then
UTIL_CHECK_TOOLS(OBJCOPY, [gobjcopy objcopy])
# Only call fixup if objcopy was found.
if test -n "$OBJCOPY"; then
UTIL_FIXUP_EXECUTABLE(OBJCOPY)
- if test "x$OPENJDK_BUILD_OS" = xsolaris; then
- # objcopy prior to 2.21.1 on solaris is broken and is not usable.
- # Rewrite objcopy version output to VALID_VERSION or BAD_VERSION.
- # - version number is last blank separate word on first line
- # - version number formats that have been seen:
- # - .
- # - ..
- OBJCOPY_VERSION=`$OBJCOPY --version | $HEAD -n 1`
- # The outer [ ] is to prevent m4 from eating the [] in the sed expression.
- [ OBJCOPY_VERSION_CHECK=`$ECHO $OBJCOPY_VERSION | $SED -n \
- -e 's/.* //' \
- -e '/^[01]\./b bad' \
- -e '/^2\./{' \
- -e ' s/^2\.//' \
- -e ' /^[0-9]$/b bad' \
- -e ' /^[0-9]\./b bad' \
- -e ' /^1[0-9]$/b bad' \
- -e ' /^1[0-9]\./b bad' \
- -e ' /^20\./b bad' \
- -e ' /^21\.0$/b bad' \
- -e ' /^21\.0\./b bad' \
- -e '}' \
- -e ':good' \
- -e 's/.*/VALID_VERSION/p' \
- -e 'q' \
- -e ':bad' \
- -e 's/.*/BAD_VERSION/p' \
- -e 'q'` ]
- if test "x$OBJCOPY_VERSION_CHECK" = xBAD_VERSION; then
- OBJCOPY=
- AC_MSG_WARN([Ignoring found objcopy since it is broken (prior to 2.21.1). No debug symbols will be generated.])
- AC_MSG_NOTICE([objcopy reports version $OBJCOPY_VERSION])
- AC_MSG_NOTICE([Note: patch 149063-01 or newer contains the correct Solaris 10 SPARC version])
- AC_MSG_NOTICE([Note: patch 149064-01 or newer contains the correct Solaris 10 X86 version])
- AC_MSG_NOTICE([Note: Solaris 11 Update 1 contains the correct version])
- fi
- fi
fi
fi
@@ -918,7 +827,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA],
fi
case $TOOLCHAIN_TYPE in
- gcc|clang|solstudio)
+ gcc|clang)
UTIL_CHECK_TOOLS(CXXFILT, [c++filt])
UTIL_CHECK_NONEMPTY(CXXFILT)
UTIL_FIXUP_EXECUTABLE(CXXFILT)
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index 533405cfd24..62459155c3f 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -261,33 +261,7 @@ MakeTargetDir = \
################################################################################
# All install-file and related macros automatically call DecodeSpace when needed.
-ifeq ($(call isTargetOs, solaris), true)
- # On Solaris, if the target is a symlink and exists, cp won't overwrite.
- # Cp has to operate in recursive mode to allow for -P flag, to preserve soft links. If the
- # name of the target file differs from the source file, rename after copy.
- # If the source and target parent directories are the same, recursive copy doesn't work
- # so we fall back on regular copy, which isn't preserving symlinks.
- define install-file
- $(call MakeTargetDir)
- $(RM) '$(call DecodeSpace, $@)'
- if [ '$(call DecodeSpace, $(dir $(call EncodeSpace, $@)))' != \
- '$(call DecodeSpace, $(dir $(call EncodeSpace, $<)))' ]; then \
- $(CP) -f -r -P '$(call DecodeSpace, $<)' \
- '$(call DecodeSpace, $(dir $(call EncodeSpace, $@)))'; \
- if [ '$(call DecodeSpace, $(notdir $(call EncodeSpace, $@)))' != \
- '$(call DecodeSpace, $(notdir $(call EncodeSpace, $(<))))' ]; then \
- $(MV) '$(call DecodeSpace, $(dir $(call EncodeSpace, $@))/$(notdir $(call EncodeSpace, $<)))' \
- '$(call DecodeSpace, $@)'; \
- fi; \
- else \
- if [ -L '$(call DecodeSpace, $<)' ]; then \
- $(ECHO) "Source file is a symlink and target is in the same directory: $< $@" ; \
- exit 1; \
- fi; \
- $(CP) -f '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'; \
- fi
- endef
-else ifeq ($(call isTargetOs, macosx), true)
+ifeq ($(call isTargetOs, macosx), true)
# On mac, extended attributes sometimes creep into the source files, which may later
# cause the creation of ._* files which confuses testing. Clear these with xattr if
# set. Some files get their write permissions removed after being copied to the
diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk
index 838573cab5d..826dca3552f 100644
--- a/make/common/Modules.gmk
+++ b/make/common/Modules.gmk
@@ -122,10 +122,6 @@ ifeq ($(call isTargetOs, windows), true)
PLATFORM_MODULES += jdk.crypto.mscapi
endif
-ifeq ($(call isTargetOs, solaris), true)
- PLATFORM_MODULES += jdk.crypto.ucrypto
-endif
-
JRE_TOOL_MODULES += \
jdk.jdwp.agent \
jdk.incubator.jpackage \
diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk
index 118f6c45136..c0978ffa84f 100644
--- a/make/common/NativeCompilation.gmk
+++ b/make/common/NativeCompilation.gmk
@@ -239,31 +239,17 @@ ifeq ($(ALLOW_ABSOLUTE_PATHS_IN_OUTPUT)-$(FILE_MACRO_CFLAGS), false-)
# When compiling with relative paths, the deps file comes out with relative
# paths.
- ifeq ($(TOOLCHAIN_TYPE), solstudio)
- define fix-deps-file
- $(SED) -e 's|\./|$(WORKSPACE_ROOT)/|g' $1.tmp > $1
- endef
- else
- define fix-deps-file
+ define fix-deps-file
$(SED) -e 's|^\([ ]*\)|\1$(WORKSPACE_ROOT)|' $1.tmp > $1
- endef
- endif
+ endef
else
# By default the MakeCommandRelative macro does nothing.
MakeCommandRelative = $1
- # Even with absolute paths on the command line, the Solaris studio compiler
- # doesn't output the full path to the object file in the generated deps files.
- # For other toolchains, no adjustment is needed.
- ifeq ($(TOOLCHAIN_TYPE), solstudio)
- define fix-deps-file
- $(SED) 's|^$$(@F):|$$@:|' $1.tmp > $1
- endef
- else
- define fix-deps-file
+ # No adjustment is needed.
+ define fix-deps-file
$(MV) $1.tmp $1
- endef
- endif
+ endef
endif
################################################################################
@@ -474,7 +460,6 @@ endef
# RC_FLAGS flags for RC.
# EMBED_MANIFEST if true, embed manifest on Windows.
# MAPFILE mapfile
-# REORDER reorder file
# USE_MAPFILE_FOR_SYMBOLS if true and this is a STATIC_BUILD, just copy the
# mapfile for the output symbols file
# CC the compiler to use, default is $(CC)
@@ -712,11 +697,6 @@ define SetupNativeCompilationBody
$1_EXTRA_ASFLAGS += $$(ASFLAGS_DEBUG_SYMBOLS)
endif
- ifneq ($$($1_REORDER), )
- $1_EXTRA_CFLAGS += $$(C_FLAG_REORDER)
- $1_EXTRA_CXXFLAGS += $$(C_FLAG_REORDER)
- endif
-
# Pass the library name for static JNI library naming
ifeq ($$($1_TYPE), STATIC_LIBRARY)
$1_EXTRA_CFLAGS += -DLIBRARY_NAME=$$($1_NAME)
@@ -750,7 +730,6 @@ define SetupNativeCompilationBody
ifeq ($$($1_WARNINGS_AS_ERRORS_$(TOOLCHAIN_TYPE)), true)
$1_EXTRA_CFLAGS += $(CFLAGS_WARNINGS_ARE_ERRORS)
$1_EXTRA_CXXFLAGS += $(CFLAGS_WARNINGS_ARE_ERRORS)
- $1_EXTRA_LDFLAGS += $(LDFLAGS_WARNINGS_ARE_ERRORS)
endif
ifeq (NONE, $$($1_OPTIMIZATION))
@@ -942,17 +921,6 @@ define SetupNativeCompilationBody
ifneq ($(DISABLE_MAPFILES), true)
$1_REAL_MAPFILE := $$($1_MAPFILE)
- ifeq ($(call isTargetOs, windows), false)
- ifneq ($$($1_REORDER), )
- $1_REAL_MAPFILE := $$($1_OBJECT_DIR)/mapfile
-
- $$($1_REAL_MAPFILE) : $$($1_MAPFILE) $$($1_REORDER)
- $$(call MakeDir, $$(@D))
- $$(CP) $$($1_MAPFILE) $$@.tmp
- $$(SED) -e 's=OUTPUTDIR=$$($1_OBJECT_DIR)=' $$($1_REORDER) >> $$@.tmp
- $$(MV) $$@.tmp $$@
- endif
- endif
endif
# Pickup extra OPENJDK_TARGET_OS_TYPE and/or OPENJDK_TARGET_OS dependent variables
@@ -986,7 +954,7 @@ define SetupNativeCompilationBody
$1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).pdb \
$$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).map
- else ifeq ($(call isTargetOs, linux solaris), true)
+ else ifeq ($(call isTargetOs, linux), true)
$1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).debuginfo
# Setup the command line creating debuginfo files, to be run after linking.
# It cannot be run separately since it updates the original target file
@@ -1113,7 +1081,7 @@ define SetupNativeCompilationBody
endif
$1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
- $$(GLOBAL_LIBS) $$($1_LIBS) $$($1_EXTRA_LIBS) $$($1_MT) \
+ $$($1_LIBS) $$($1_EXTRA_LIBS) $$($1_MT) \
$$($1_CREATE_DEBUGINFO_CMDS) $$($1_MANIFEST_VERSION) \
$$($1_STRIP_CMD)
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
@@ -1172,7 +1140,7 @@ define SetupNativeCompilationBody
$$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_link, \
$$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
- $(LD_OUT_OPTION)$$($1_TARGET) $$($1_LD_OBJ_ARG) $$($1_RES) $$(GLOBAL_LIBS) \
+ $(LD_OUT_OPTION)$$($1_TARGET) $$($1_LD_OBJ_ARG) $$($1_RES) \
$$($1_LIBS) $$($1_EXTRA_LIBS)) \
| $(GREP) -v "^ Creating library .*\.lib and object .*\.exp" || \
test "$$$$?" = "1" ; \
@@ -1182,7 +1150,7 @@ define SetupNativeCompilationBody
$$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_link, \
$$(if $$($1_LINK_OBJS_RELATIVE), $$(CD) $$(OUTPUTDIR) ; ) \
$$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
- $(LD_OUT_OPTION)$$($1_TARGET) $$($1_LD_OBJ_ARG) $$($1_RES) $$(GLOBAL_LIBS) \
+ $(LD_OUT_OPTION)$$($1_TARGET) $$($1_LD_OBJ_ARG) $$($1_RES) \
$$($1_LIBS) $$($1_EXTRA_LIBS)) ; \
$$($1_CREATE_DEBUGINFO_CMDS)
$$($1_STRIP_CMD)
diff --git a/make/common/TestFilesCompilation.gmk b/make/common/TestFilesCompilation.gmk
index 999aec7db29..d0ab1cce988 100644
--- a/make/common/TestFilesCompilation.gmk
+++ b/make/common/TestFilesCompilation.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -98,7 +98,6 @@ define SetupTestFilesCompilationBody
DISABLED_WARNINGS_gcc := format undef unused-function unused-value, \
DISABLED_WARNINGS_clang := undef format-nonliteral \
missing-field-initializers sometimes-uninitialized, \
- DISABLED_WARNINGS_CXX_solstudio := wvarhidenmem doubunder, \
LIBS := $$($1_LIBS_$$(name)), \
TOOLCHAIN := $(if $$(filter %.cpp, $$(file)), TOOLCHAIN_LINK_CXX, TOOLCHAIN_DEFAULT), \
OPTIMIZATION := $$(if $$($1_OPTIMIZATION_$$(name)),$$($1_OPTIMIZATION_$$(name)),LOW), \
diff --git a/make/common/Utils.gmk b/make/common/Utils.gmk
index 8bf8c15476a..794d5789ebc 100644
--- a/make/common/Utils.gmk
+++ b/make/common/Utils.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -296,8 +296,8 @@ check-jvm-variant = \
# Returns true if the actual property matches one of the properties in the list,
# and false otherwise.
#
-# Examples: $(call isTargetOs, linux solaris) will return true when executed
-# on either linux or solaris, and false otherwise.
+# Examples: $(call isTargetOs, linux windows) will return true when executed
+# on either linux or windows, and false otherwise.
# $(call isBuildCpuArch, x86) will return true iff the build CPU Arch is x86.
isTargetOs = \
diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk
index 788f9f1783b..8620d48d895 100644
--- a/make/common/modules/LauncherCommon.gmk
+++ b/make/common/modules/LauncherCommon.gmk
@@ -40,8 +40,6 @@ ifeq ($(TOOLCHAIN_TYPE), gcc)
LDFLAGS_JDKEXE += -Wl,--exclude-libs,ALL
else ifeq ($(TOOLCHAIN_TYPE), clang)
LAUNCHER_CFLAGS += -fvisibility=hidden
-else ifeq ($(TOOLCHAIN_TYPE), solstudio)
- LAUNCHER_CFLAGS += -xldscope=hidden
endif
LAUNCHER_SRC := $(TOPDIR)/src/java.base/share/native/launcher
@@ -143,7 +141,6 @@ define SetupBuildLauncherBody
-DLAUNCHER_NAME='"$$(LAUNCHER_NAME)"' \
-DPROGNAME='"$1"' \
$$($1_CFLAGS), \
- CFLAGS_solaris := -KPIC, \
CFLAGS_windows := $$($1_CFLAGS_windows), \
DISABLED_WARNINGS_gcc := unused-function, \
LDFLAGS := $$(LDFLAGS_JDKEXE) \
@@ -153,14 +150,11 @@ define SetupBuildLauncherBody
-L$(call FindLibDirForModule, java.base), \
LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \
-L$(call FindLibDirForModule, java.base), \
- LDFLAGS_solaris := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \
- -L$(call FindLibDirForModule, java.base), \
LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
LIBS_linux := -ljli -lpthread $(LIBDL), \
LIBS_macosx := -ljli -framework Cocoa -framework Security \
-framework ApplicationServices, \
- LIBS_solaris := -ljli -lthread $(LIBDL), \
LIBS_aix := -ljli_static, \
LIBS_windows := $$($1_WINDOWS_JLI_LIB) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libjava/java.lib, \
diff --git a/make/common/modules/LibCommon.gmk b/make/common/modules/LibCommon.gmk
index 75cb9ca1d9a..f841ad9b166 100644
--- a/make/common/modules/LibCommon.gmk
+++ b/make/common/modules/LibCommon.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -49,10 +49,6 @@ else ifeq ($(TOOLCHAIN_TYPE), clang)
CFLAGS_JDKLIB += -fvisibility=hidden
CXXFLAGS_JDKLIB += -fvisibility=hidden
EXPORT_ALL_SYMBOLS := -fvisibility=default
-else ifeq ($(TOOLCHAIN_TYPE), solstudio)
- CFLAGS_JDKLIB += -xldscope=hidden
- CXXFLAGS_JDKLIB += -xldscope=hidden
- EXPORT_ALL_SYMBOLS := -xldscope=global
endif
# Put the libraries here.
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index f80382b669d..befee0d95b8 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -239,8 +239,8 @@ var getJibProfilesCommon = function (input, data) {
// List of the main profile names used for iteration
common.main_profile_names = [
- "linux-x64", "linux-x86", "macosx-x64", "solaris-x64",
- "solaris-sparcv9", "windows-x64", "windows-x86",
+ "linux-x64", "linux-x86", "macosx-x64",
+ "windows-x64", "windows-x86",
"linux-aarch64", "linux-arm32", "linux-ppc64le", "linux-s390x"
];
@@ -429,22 +429,6 @@ var getJibProfilesProfiles = function (input, common, data) {
"--with-macosx-version-max=10.9.0"),
},
- "solaris-x64": {
- target_os: "solaris",
- target_cpu: "x64",
- dependencies: ["devkit", "cups"],
- configure_args: concat(common.configure_args_64bit,
- "--with-zlib=system", "--enable-dtrace", "--enable-deprecated-ports=yes"),
- },
-
- "solaris-sparcv9": {
- target_os: "solaris",
- target_cpu: "sparcv9",
- dependencies: ["devkit", "cups"],
- configure_args: concat(common.configure_args_64bit,
- "--with-zlib=system", "--enable-dtrace", "--enable-deprecated-ports=yes"),
- },
-
"windows-x64": {
target_os: "windows",
target_cpu: "x64",
@@ -533,7 +517,7 @@ var getJibProfilesProfiles = function (input, common, data) {
"ANT_HOME": input.get("ant", "home_path")
}
};
- [ "linux-x64", "macosx-x64", "solaris-sparcv9", "solaris-x64", "windows-x64"]
+ [ "linux-x64", "macosx-x64", "windows-x64"]
.forEach(function (name) {
var maketestName = name + "-testmake";
profiles[maketestName] = concatObjects(profiles[name], testmakeBase);
@@ -607,7 +591,7 @@ var getJibProfilesProfiles = function (input, common, data) {
// Bootcycle profiles runs the build with itself as the boot jdk. This can
// be done in two ways. Either using the builtin bootcycle target in the
// build system. Or by supplying the main jdk build as bootjdk to configure.
- [ "linux-x64", "macosx-x64", "solaris-sparcv9", "windows-x64"]
+ [ "linux-x64", "macosx-x64", "windows-x64" ]
.forEach(function (name) {
var bootcycleName = name + "-bootcycle";
var bootcyclePrebuiltName = name + "-bootcycle-prebuilt";
@@ -634,7 +618,7 @@ var getJibProfilesProfiles = function (input, common, data) {
});
// JCov profiles build JCov-instrumented JDK image based on images provided through dependencies.
- [ "linux-aarch64", "linux-x64", "macosx-x64", "solaris-sparcv9", "windows-x64"]
+ [ "linux-aarch64", "linux-x64", "macosx-x64", "windows-x64" ]
.forEach(function (name) {
var jcovName = name + "-jcov";
profiles[jcovName] = clone(common.main_profile_base);
@@ -663,12 +647,6 @@ var getJibProfilesProfiles = function (input, common, data) {
platform: "osx-x64",
jdk_subdir: "jdk-" + data.version + ".jdk/Contents/Home",
},
- "solaris-x64": {
- platform: "solaris-x64",
- },
- "solaris-sparcv9": {
- platform: "solaris-sparcv9",
- },
"windows-x64": {
platform: "windows-x64",
jdk_suffix: "zip",
@@ -795,7 +773,7 @@ var getJibProfilesProfiles = function (input, common, data) {
});
// Artifacts of JCov profiles
- [ "linux-aarch64", "linux-x64", "macosx-x64", "solaris-sparcv9", "windows-x64"]
+ [ "linux-aarch64", "linux-x64", "macosx-x64", "windows-x64" ]
.forEach(function (name) {
var o = artifactData[name]
var jdk_subdir = (o.jdk_subdir != null ? o.jdk_subdir : "jdk-" + data.version);
@@ -984,8 +962,6 @@ var getJibProfilesDependencies = function (input, common) {
var devkit_platform_revisions = {
linux_x64: "gcc9.2.0-OL6.4+1.0",
macosx_x64: "Xcode10.1-MacOSX10.14+1.0",
- solaris_x64: "SS12u4-Solaris11u1+1.0",
- solaris_sparcv9: "SS12u6-Solaris11u3+1.0",
windows_x64: "VS2019-16.5.3+1.0",
linux_aarch64: "gcc9.2.0-OL7.6+1.0",
linux_arm: "gcc8.2.0-Fedora27+1.0",
@@ -1040,11 +1016,6 @@ var getJibProfilesDependencies = function (input, common) {
environment_path: common.boot_jdk_home + "/bin"
}
}
- if (input.build_cpu == 'sparcv9') {
- boot_jdk.file = "bundles/openjdk/GPL/" + boot_jdk_platform
- + "/openjdk-" + common.boot_jdk_version + "_"
- + boot_jdk_platform + "_bin" + boot_jdk_ext;
- }
var dependencies = {
boot_jdk: boot_jdk,
diff --git a/make/data/fontconfig/solaris.fontconfig.properties b/make/data/fontconfig/solaris.fontconfig.properties
deleted file mode 100644
index 4d21d1924eb..00000000000
--- a/make/data/fontconfig/solaris.fontconfig.properties
+++ /dev/null
@@ -1,516 +0,0 @@
-#
-#
-# Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# Version
-
-version=1
-
-# Component Font Mappings
-
-allfonts.chinese-gb2312=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-gbk=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-gb18030-0=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-gb18030-1=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-cns11643-1=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-cns11643-2=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-cns11643-3=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-big5=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.chinese-hkscs=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.dingbats=-microsoft-wingdings-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific
-allfonts.japanese-x0212=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.korean=-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.korean-johab=-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-allfonts.symbol=-monotype-symbol-medium-r-normal--*-%d-*-*-p-*-adobe-symbol
-allfonts.bengali=-misc-lohit bengali-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.gujarati=-misc-lohit gujarati-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.hindi=-misc-lohit hindi-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.kannada=-misc-lohit kannada-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.malayalam=-misc-lohit malayalam-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.marathi=-misc-lohit marathi-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.tamil=-misc-lohit tamil-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.telugu=-misc-lohit telugu-medium-r-normal--0-0-0-0-p-0-iso10646-1
-allfonts.dejavusans=-misc-dejavu sans-medium-r-normal--0-0-0-0-p-0-iso10646-1
-
-serif.plain.arabic=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.cyrillic-iso8859-5=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.cyrillic-cp1251=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.cyrillic-koi8-r=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.greek=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.hebrew=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.plain.latin-1=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.latin-2=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.latin-5=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.latin-7=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.latin-9=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.plain.thai=-monotype-angsana new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-
-serif.bold.arabic=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.cyrillic-iso8859-5=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.cyrillic-cp1251=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.cyrillic-koi8-r=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.greek=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.hebrew=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.bold.latin-1=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.latin-2=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.latin-5=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.latin-7=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.latin-9=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bold.thai=-monotype-angsana new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-
-serif.italic.arabic=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.cyrillic-iso8859-5=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.cyrillic-cp1251=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.cyrillic-koi8-r=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.greek=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.hebrew=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.italic.latin-1=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.latin-2=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.latin-5=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.latin-7=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.latin-9=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.italic.thai=-monotype-angsana new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-
-serif.bolditalic.arabic=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.cyrillic-iso8859-5=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.cyrillic-cp1251=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.cyrillic-koi8-r=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.greek=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.hebrew=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-serif.bolditalic.latin-1=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.latin-2=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.latin-5=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.latin-7=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.latin-9=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-serif.bolditalic.thai=-monotype-angsana new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-
-sansserif.plain.arabic=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.cyrillic-iso8859-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.cyrillic-cp1251=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.cyrillic-koi8-r=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.greek=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.hebrew=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.plain.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.plain.latin-1=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.latin-2=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.latin-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.latin-7=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.latin-9=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.plain.thai=-monotype-browallia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-
-sansserif.bold.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.cyrillic-iso8859-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.cyrillic-cp1251=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.cyrillic-koi8-r=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.greek=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.hebrew=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.bold.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.bold.latin-1=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.latin-2=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.latin-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.latin-7=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.latin-9=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bold.thai=-monotype-browallia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-
-sansserif.italic.arabic=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.cyrillic-iso8859-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.cyrillic-cp1251=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.cyrillic-koi8-r=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.greek=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.hebrew=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.italic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.italic.latin-1=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.latin-2=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.latin-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.latin-7=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.latin-9=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.italic.thai=-monotype-browallia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-
-sansserif.bolditalic.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.cyrillic-iso8859-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.cyrillic-cp1251=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.cyrillic-koi8-r=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.greek=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.hebrew=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.bolditalic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-sansserif.bolditalic.latin-1=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.latin-2=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.latin-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.latin-7=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.latin-9=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-sansserif.bolditalic.thai=-monotype-browallia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-
-monospaced.plain.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.cyrillic-iso8859-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.cyrillic-cp1251=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.cyrillic-koi8-r=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.greek=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.hebrew=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.plain.latin-1=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.latin-2=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.latin-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.latin-7=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.latin-9=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.plain.thai=-monotype-cordia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-
-monospaced.bold.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.cyrillic-iso8859-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.cyrillic-cp1251=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.cyrillic-koi8-r=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.greek=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.hebrew=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.bold.latin-1=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.latin-2=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.latin-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.latin-7=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.latin-9=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bold.thai=-monotype-cordia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-
-monospaced.italic.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.cyrillic-iso8859-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.cyrillic-cp1251=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.cyrillic-koi8-r=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.greek=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.hebrew=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.italic.latin-1=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.latin-2=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.latin-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.latin-7=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.latin-9=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.italic.thai=-monotype-cordia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-
-monospaced.bolditalic.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.cyrillic-iso8859-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.cyrillic-cp1251=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.cyrillic-koi8-r=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.greek=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.hebrew=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-monospaced.bolditalic.latin-1=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.latin-2=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.latin-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.latin-7=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.latin-9=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-monospaced.bolditalic.thai=-monotype-cordia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-
-dialog.plain.arabic=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.cyrillic-iso8859-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.cyrillic-cp1251=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.cyrillic-koi8-r=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.greek=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.hebrew=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.plain.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.plain.latin-1=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.latin-2=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.latin-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.latin-7=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.latin-9=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.plain.thai=-monotype-browallia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-
-dialog.bold.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.cyrillic-iso8859-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.cyrillic-cp1251=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.cyrillic-koi8-r=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.greek=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.hebrew=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.bold.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.bold.latin-1=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.latin-2=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.latin-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.latin-7=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.latin-9=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bold.thai=-monotype-browallia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-
-dialog.italic.arabic=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.cyrillic-iso8859-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.cyrillic-cp1251=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.cyrillic-koi8-r=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.greek=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.hebrew=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.italic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.italic.latin-1=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.latin-2=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.latin-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.latin-7=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.latin-9=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.italic.thai=-monotype-browallia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-
-dialog.bolditalic.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.cyrillic-iso8859-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.cyrillic-cp1251=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.cyrillic-koi8-r=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.greek=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.hebrew=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.bolditalic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialog.bolditalic.latin-1=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.latin-2=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.latin-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.latin-7=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.latin-9=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialog.bolditalic.thai=-monotype-browallia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-
-dialoginput.plain.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.cyrillic-iso8859-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.cyrillic-cp1251=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.cyrillic-koi8-r=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.greek=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.hebrew=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.plain.latin-1=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.latin-2=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.latin-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.latin-7=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.latin-9=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.plain.thai=-monotype-cordia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-
-dialoginput.bold.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.cyrillic-iso8859-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.cyrillic-cp1251=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.cyrillic-koi8-r=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.greek=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.hebrew=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.bold.latin-1=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.latin-2=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.latin-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.latin-7=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.latin-9=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bold.thai=-monotype-cordia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-
-dialoginput.italic.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.cyrillic-iso8859-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.cyrillic-cp1251=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.cyrillic-koi8-r=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.greek=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.hebrew=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.italic.latin-1=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.latin-2=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.latin-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.latin-7=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.latin-9=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.italic.thai=-monotype-cordia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
-
-dialoginput.bolditalic.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.cyrillic-iso8859-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.cyrillic-cp1251=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.cyrillic-koi8-r=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.greek=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.hebrew=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
-dialoginput.bolditalic.latin-1=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.latin-2=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.latin-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.latin-7=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.latin-9=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-dialoginput.bolditalic.thai=-monotype-cordia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
-
-# Search Sequences
-
-sequence.allfonts=latin-1
-
-sequence.allfonts.Big5=latin-1,chinese-big5
-
-sequence.allfonts.Big5-HKSCS-2001=latin-1,chinese-big5,chinese-hkscs
-
-sequence.allfonts.windows-1251=cyrillic-cp1251,latin-1
-
-sequence.allfonts.GB2312=latin-1,chinese-gb2312
-
-sequence.allfonts.x-eucJP-Open=latin-1,japanese-x0201,japanese-x0208,japanese-x0212
-
-sequence.allfonts.EUC-KR=latin-1,korean
-
-sequence.allfonts.x-EUC-TW=latin-1,chinese-cns11643-1,chinese-cns11643-2,chinese-cns11643-3
-
-sequence.allfonts.GBK=latin-1,chinese-gbk
-
-sequence.allfonts.GB18030=latin-1,chinese-gb18030-0,chinese-gb18030-1
-
-sequence.allfonts.ISO-8859-2=latin-2,latin-1
-
-sequence.allfonts.ISO-8859-5=cyrillic-iso8859-5,latin-1
-
-sequence.allfonts.ISO-8859-6=arabic,latin-1
-
-sequence.allfonts.ISO-8859-7=latin-1,greek
-
-sequence.allfonts.ISO-8859-8=latin-1,hebrew
-
-sequence.allfonts.ISO-8859-9=latin-5,latin-1
-
-sequence.allfonts.ISO-8859-13=latin-7,latin-1
-
-sequence.allfonts.ISO-8859-15=latin-9
-
-sequence.allfonts.KOI8-R=cyrillic-koi8-r,latin-1
-
-sequence.allfonts.x-PCK=latin-1,japanese-x0201,japanese-x0208,japanese-x0212
-
-sequence.allfonts.TIS-620=latin-1,thai
-
-sequence.allfonts.UTF-8=latin-1
-sequence.allfonts.UTF-8.en=latin-1
-sequence.allfonts.UTF-8.hi=latin-1,hindi
-sequence.allfonts.UTF-8.be=latin-1,bengali
-sequence.allfonts.UTF-8.te=latin-1,telugu
-sequence.allfonts.UTF-8.mr=latin-1,marathi
-sequence.allfonts.UTF-8.ta=latin-1,tamil
-sequence.allfonts.UTF-8.gu=latin-1,gujarati
-sequence.allfonts.UTF-8.kn=latin-1,kannada
-sequence.allfonts.UTF-8.ma=latin-1,malayalam
-
-sequence.allfonts.UTF-8.ko=latin-1,korean-johab,japanese-x0201,japanese-x0208,japanese-x0212
-
-sequence.allfonts.UTF-8.th=latin-1,thai
-
-sequence.allfonts.UTF-8.zh.CN=latin-1,chinese-gb18030-0,chinese-gb18030-1,chinese-big5,chinese-hkscs
-
-sequence.allfonts.UTF-8.zh.HK=latin-1,chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1
-
-sequence.allfonts.UTF-8.zh.TW=latin-1,chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1
-
-# the fallback sequence omits the following character subsets:
-# - chinese: all same file : just use chinese-gb18030-0
-# - japanese-x0208: same files as japanese-x0201
-# - japanese-x0212: same files as japanese-x0201
-# - korean: same file as korean-johab
-sequence.fallback=latin-1,latin-2,latin-7,cyrillic-iso8859-5,greek,latin-5,latin-9,\
- arabic,hebrew,thai,\
- chinese-gb18030-0,\
- japanese-x0201,korean-johab,\
- hindi,bengali,telugu,marathi,tamil,gujarati,kannada,malayalam,\
- dejavusans,dingbats,symbol
-
-# Font File Names
-
-filename.-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arial.ttf
-filename.-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/ariali.ttf
-filename.-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbd.ttf
-filename.-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbi.ttf
-filename.-monotype-courier_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cour.ttf
-filename.-monotype-courier_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/couri.ttf
-filename.-monotype-courier_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbd.ttf
-filename.-monotype-courier_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbi.ttf
-filename.-monotype-times_new_roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/times.ttf
-filename.-monotype-times_new_roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesi.ttf
-filename.-monotype-times_new_roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbd.ttf
-filename.-monotype-times_new_roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbi.ttf
-
-filename.-monotype-angsana_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsa.ttf
-filename.-monotype-angsana_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsai.ttf
-filename.-monotype-angsana_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsab.ttf
-filename.-monotype-angsana_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsaz.ttf
-filename.-monotype-browallia_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browa.ttf
-filename.-monotype-browallia_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browai.ttf
-filename.-monotype-browallia_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browab.ttf
-filename.-monotype-browallia_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browaz.ttf
-filename.-monotype-cordia_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordia.ttf
-filename.-monotype-cordia_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiai.ttf
-filename.-monotype-cordia_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiab.ttf
-filename.-monotype-cordia_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiaz.ttf
-
-filename.-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/ipafont/ipag.otf
-filename.-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/ipafont/ipam.otf
-filename.-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/hanyang/h2gtrm.ttf
-filename.-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/arphic/uming.ttf
-filename.-monotype-symbol-medium-r-normal--*-%d-*-*-p-*-adobe-symbol=/usr/share/fonts/TrueType/core/symbol.ttf
-filename.-microsoft-wingdings-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific=/usr/share/fonts/TrueType/core/wingdings.ttf
-filename.-misc-lohit_bengali-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Bengali.ttf
-filename.-misc-lohit_gujarati-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Gujarati.ttf
-filename.-misc-lohit_hindi-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Hindi.ttf
-filename.-misc-lohit_kannada-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Kannada.ttf
-filename.-misc-lohit_malayalam-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Malayalam.ttf
-filename.-misc-lohit_marathi-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Marathi.ttf
-filename.-misc-lohit_tamil-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Tamil.ttf
-filename.-misc-lohit_telugu-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Telugu.ttf
-filename.-misc-dejavu_sans-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/dejavu/DejaVuSans.ttf
-
-# AWT X11 font paths
-awtfontpath.latin-1=/usr/share/fonts/TrueType/core
-awtfontpath.latin-2=/usr/share/fonts/TrueType/core
-awtfontpath.latin-5=/usr/share/fonts/TrueType/core
-awtfontpath.latin-7=/usr/share/fonts/TrueType/core
-awtfontpath.latin-9=/usr/share/fonts/TrueType/core
-awtfontpath.hebrew=/usr/share/fonts/TrueType/core
-awtfontpath.arabic=/usr/share/fonts/TrueType/core
-awtfontpath.thai=/usr/share/fonts/TrueType/core
-awtfontpath.greek=/usr/share/fonts/TrueType/core
-awtfontpath.cyrillic-iso8859-5=/usr/share/fonts/TrueType/core
-awtfontpath.cyrillic-cp1251=/usr/share/fonts/TrueType/core
-awtfontpath.cyrillic-koi8-r=/usr/share/fonts/TrueType/core
-awtfontpath.korean=/usr/share/fonts/TrueType/hanyang
-awtfontpath.korean-johab=/usr/share/fonts/TrueType/hanyang
-awtfontpath.japanese-x0201=/usr/share/fonts/TrueType/ipafont
-awtfontpath.japanese-x0208=/usr/share/fonts/TrueType/ipafont
-awtfontpath.japanese-x0212=/usr/share/fonts/TrueType/ipafont
-awtfontpath.chinese-gbk=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-cns11643-1=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-cns11643-2=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-cns11643-3=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-big5=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-gb2312=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-gb18030-0=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-gb18030-1=/usr/share/fonts/TrueType/arphic
-awtfontpath.chinese-hkscs=/usr/share/fonts/TrueType/arphic
-awtfontpath.bengali=/usr/share/fonts/TrueType/lohit
-awtfontpath.gujarati=/usr/share/fonts/TrueType/lohit
-awtfontpath.hindi=/usr/share/fonts/TrueType/lohit
-awtfontpath.kannada=/usr/share/fonts/TrueType/lohit
-awtfontpath.malayalam=/usr/share/fonts/TrueType/lohit
-awtfontpath.marathi=/usr/share/fonts/TrueType/lohit
-awtfontpath.tamil=/usr/share/fonts/TrueType/lohit
-awtfontpath.telugu=/usr/share/fonts/TrueType/lohit
-awtfontpath.dejavusans=/usr/share/fonts/TrueType/dejavu
-
-# Appended Font Path
-
diff --git a/make/devkit/createSolarisDevkit12.4.sh b/make/devkit/createSolarisDevkit12.4.sh
deleted file mode 100644
index b60e9e6d573..00000000000
--- a/make/devkit/createSolarisDevkit12.4.sh
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# This script creates a devkit for building OpenJDK on Solaris by copying
-# part of a Solaris Studio installation and cretaing a sysroot by installing
-# a limited set of system packages. It is assumed that a suitable pkg
-# publisher is configured for the system where the script is executed.
-#
-# The Solaris Studio installation must contain at least these packages:
-# developer/solarisstudio-124/backend 12.4-1.0.6.0 i--
-# developer/solarisstudio-124/c++ 12.4-1.0.10.0 i--
-# developer/solarisstudio-124/cc 12.4-1.0.4.0 i--
-# developer/solarisstudio-124/library/c++-libs 12.4-1.0.10.0 i--
-# developer/solarisstudio-124/library/math-libs 12.4-1.0.0.1 i--
-# developer/solarisstudio-124/library/studio-gccrt 12.4-1.0.0.1 i--
-# developer/solarisstudio-124/studio-common 12.4-1.0.0.1 i--
-# developer/solarisstudio-124/studio-ja 12.4-1.0.0.1 i--
-# developer/solarisstudio-124/studio-legal 12.4-1.0.0.1 i--
-# developer/solarisstudio-124/studio-zhCN 12.4-1.0.0.1 i--
-# In particular backend 12.4-1.0.6.0 contains a critical patch for the sparc
-# version.
-#
-# erik.joelsson@oracle.com
-
-USAGE="$0 "
-
-if [ "$1" = "" ] || [ "$2" = "" ]; then
- echo $USAGE
- exit 1
-fi
-
-SOLARIS_STUDIO_VERSION=12u4
-SOLARIS_VERSION=11u1
-case `uname -p` in
- i*)
- ARCH=x86
- ;;
- sparc*)
- ARCH=sparc
- ;;
-esac
-
-SOLARIS_STUDIO_SRC=$1
-GNU_MAKE=$2
-
-SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)"
-BUILD_DIR="${SCRIPT_DIR}/../../build/devkit"
-
-DEVKIT_NAME=SS${SOLARIS_STUDIO_VERSION}-Solaris${SOLARIS_VERSION}
-DEVKIT_ROOT=${BUILD_DIR}/${DEVKIT_NAME}
-BUNDLE_NAME=${DEVKIT_NAME}.tar.gz
-BUNDLE=${BUILD_DIR}/${BUNDLE_NAME}
-INSTALL_ROOT=${BUILD_DIR}/install-root-$SOLARIS_VERSION
-INSTALL_ROOT_TOOLS=${BUILD_DIR}/install-root-tools-$SOLARIS_VERSION
-SYSROOT=${DEVKIT_ROOT}/sysroot
-SOLARIS_STUDIO_SUBDIR=SS${SOLARIS_STUDIO_VERSION}
-SOLARIS_STUDIO_DIR=${DEVKIT_ROOT}/${SOLARIS_STUDIO_SUBDIR}
-
-# Extract the publisher from the system
-if [ -z "${PUBLISHER_URI}" ]; then
- PUBLISHER_URI="$(pkg publisher solaris | grep URI | awk '{ print $3 }')"
-fi
-
-if [ ! -d $INSTALL_ROOT ]; then
- echo "Creating $INSTALL_ROOT and installing packages"
- pkg image-create $INSTALL_ROOT
- pkg -R $INSTALL_ROOT set-publisher -P -g ${PUBLISHER_URI} solaris
- pkg -R $INSTALL_ROOT install --accept $(cat solaris11.1-package-list.txt)
-else
- echo "Skipping installing packages"
-fi
-
-# Since we have implicitly been running 11.2 tools for a long time, we need
-# to pick them for the tools dir in the devkit. Create a separate install-root
-# for it.
-if [ ! -d $INSTALL_ROOT_TOOLS ]; then
- echo "Creating $INSTALL_ROOT_TOOLS and installing packages"
- pkg image-create $INSTALL_ROOT_TOOLS
- pkg -R $INSTALL_ROOT_TOOLS set-publisher -P -g ${PUBLISHER_URI} solaris
- sudo pkg -R $INSTALL_ROOT_TOOLS install --accept \
- entire@0.5.11-0.175.2.5.0.5.0 \
- system/linker \
- developer/base-developer-utilities \
- developer/gnu-binutils
-else
- echo "Skipping installing tools packages"
-fi
-
-if [ ! -d $SYSROOT ]; then
- echo "Copying from $INSTALL_ROOT to $SYSROOT"
- mkdir -p $SYSROOT
- cp -rH $INSTALL_ROOT/lib $SYSROOT/
- mkdir $SYSROOT/usr
- cp -rH $INSTALL_ROOT/usr/lib $SYSROOT/usr/
- cp -rH $INSTALL_ROOT/usr/include $SYSROOT/usr/
- pkg -R $INSTALL_ROOT list > $SYSROOT/pkg-list.txt
-else
- echo "Skipping copying to $SYSROOT"
-fi
-
-if [ ! -d $DEVKIT_ROOT/tools ]; then
- echo "Copying from $INSTALL_ROOT_TOOLS to $DEVKIT_ROOT/tools"
- # Some of the tools in sysroot are needed in the OpenJDK build. We need
- # to copy them into a tools dir, including their specific libraries.
- mkdir -p $DEVKIT_ROOT/tools/usr/bin/sparcv9 $DEVKIT_ROOT/tools/lib/sparcv9 \
- $DEVKIT_ROOT/tools/usr/gnu/bin
- cp $INSTALL_ROOT_TOOLS/usr/bin/{ar,nm,strip,ld,ldd} \
- $DEVKIT_ROOT/tools/usr/bin/
- cp $INSTALL_ROOT_TOOLS/usr/bin/sparcv9/{ar,nm,strip,ld,ldd} \
- $DEVKIT_ROOT/tools/usr/bin/sparcv9/
- cp $INSTALL_ROOT_TOOLS/usr/sbin/dtrace $DEVKIT_ROOT/tools/usr/bin/
- cp $INSTALL_ROOT_TOOLS/usr/sbin/sparcv9/dtrace $DEVKIT_ROOT/tools/usr/bin/sparcv9/
- cp -rH $INSTALL_ROOT_TOOLS/usr/gnu/bin/* $DEVKIT_ROOT/tools/usr/gnu/bin/
- cp $INSTALL_ROOT_TOOLS/lib/{libelf.so*,libld.so*,liblddbg.so*} \
- $DEVKIT_ROOT/tools/lib/
- cp $INSTALL_ROOT_TOOLS/lib/sparcv9/{libelf.so*,libld.so*,liblddbg.so*} \
- $DEVKIT_ROOT/tools/lib/sparcv9/
- for t in $(ls $DEVKIT_ROOT/tools/usr/gnu/bin); do
- if [ -f $DEVKIT_ROOT/tools/usr/gnu/bin/$t ]; then
- ln -s ../gnu/bin/$t $DEVKIT_ROOT/tools/usr/bin/g$t
- fi
- done
-else
- echo "Skipping copying to tools dir $DEVKIT_ROOT/tools"
-fi
-
-if [ ! -d $SOLARIS_STUDIO_DIR ]; then
- echo "Copying Solaris Studio from $SOLARIS_STUDIO_SRC"
- mkdir -p ${SOLARIS_STUDIO_DIR}
- cp -rH $SOLARIS_STUDIO_SRC/. ${SOLARIS_STUDIO_DIR}/
- # Solaris Studio 12.4 requires /lib/libmmheap.so.1 to run, but this lib is not
- # installed by default on all Solaris systems. Sneak it in from the sysroot to
- # make it run OOTB on more systems.
- cp $SYSROOT/lib/libmmheap.so.1 $SOLARIS_STUDIO_DIR/lib/compilers/sys/
-else
- echo "Skipping copying of Solaris Studio"
-fi
-
-echo "Copying gnu make to $DEVKIT_ROOT/bin"
-cp $GNU_MAKE $DEVKIT_ROOT/tools/usr/bin/
-if [ ! -e $DEVKIT_ROOT/tools/usr/bin/gmake ]; then
- ln -s make $DEVKIT_ROOT/tools/usr/bin/gmake
-fi
-
-# Create the devkit.info file
-echo Creating devkit.info
-INFO_FILE=$DEVKIT_ROOT/devkit.info
-rm -f $INFO_FILE
-echo "# This file describes to configure how to interpret the contents of this devkit" >> $INFO_FILE
-echo "DEVKIT_NAME=\"Solaris Studio $SOLARIS_STUDIO_VERSION - Solaris $SOLARIS_VERSION - $ARCH\"" >> $INFO_FILE
-echo "DEVKIT_TOOLCHAIN_PATH=\"\$DEVKIT_ROOT/$SOLARIS_STUDIO_SUBDIR/bin:\$DEVKIT_ROOT/bin\"" >> $INFO_FILE
-echo "DEVKIT_EXTRA_PATH=\"\$DEVKIT_ROOT/tools/usr/bin\"" >> $INFO_FILE
-echo "DEVKIT_SYSROOT=\"\$DEVKIT_ROOT/sysroot\"" >> $INFO_FILE
-
-if [ ! -e $BUNDLE ]; then
- echo "Creating $BUNDLE from $DEVKIT_ROOT"
- cd $DEVKIT_ROOT/..
- tar zcf $BUNDLE $DEVKIT_NAME
-else
- echo "Skipping creation of $BUNDLE"
-fi
diff --git a/make/devkit/createSolarisDevkit12.6.sh b/make/devkit/createSolarisDevkit12.6.sh
deleted file mode 100644
index 9321c5d3dcb..00000000000
--- a/make/devkit/createSolarisDevkit12.6.sh
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# This script creates a devkit for building OpenJDK on Solaris by copying
-# part of a Solaris Studio installation and cretaing a sysroot by installing
-# a limited set of system packages. It is assumed that a suitable pkg
-# publisher is configured for the system where the script is executed.
-#
-# Note that you will need to be able to sudo to root to run the pkg install
-# part of this script. It should not affect the running system, but only
-# install in a separate temporary image.
-#
-# The Solaris Studio installation must contain at least these packages:
-#developer/developerstudio-126/backend 12.6-1.0.0.1
-#developer/developerstudio-126/c++ 12.6-1.0.2.0
-#developer/developerstudio-126/cc 12.6-1.0.1.0
-#developer/developerstudio-126/dbx 12.6-1.0.0.1
-#developer/developerstudio-126/library/c++-libs 12.6-1.0.2.0
-#developer/developerstudio-126/library/c-libs 12.6-1.0.0.1
-#developer/developerstudio-126/library/f90-libs 12.6-1.0.0.1
-#developer/developerstudio-126/library/math-libs 12.6-1.0.0.1
-#developer/developerstudio-126/library/studio-gccrt 12.6-1.0.0.1
-#developer/developerstudio-126/studio-common 12.6-1.0.0.1
-#developer/developerstudio-126/studio-ja 12.6-1.0.0.1
-#developer/developerstudio-126/studio-legal 12.6-1.0.0.1
-#developer/developerstudio-126/studio-zhCN 12.6-1.0.0.1
-#
-# erik.joelsson@oracle.com
-
-USAGE="$0 "
-
-if [ "$1" = "" ]; then
- echo $USAGE
- exit 1
-fi
-
-SOLARIS_STUDIO_VERSION=12u6
-SOLARIS_VERSION=11u3
-SOLARIS_ENTIRE_VERSION=0.5.11-0.175.3.20.0.6.0
-case `uname -p` in
- i*)
- ARCH=x86
- ;;
- sparc*)
- ARCH=sparc
- ;;
-esac
-
-SOLARIS_STUDIO_SRC=$1
-
-SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)"
-BUILD_DIR="${SCRIPT_DIR}/../../build/devkit"
-
-DEVKIT_NAME=SS${SOLARIS_STUDIO_VERSION}-Solaris${SOLARIS_VERSION}
-DEVKIT_ROOT=${BUILD_DIR}/${DEVKIT_NAME}
-BUNDLE_NAME=${DEVKIT_NAME}.tar.gz
-BUNDLE=${BUILD_DIR}/${BUNDLE_NAME}
-INSTALL_ROOT=${BUILD_DIR}/install-root-$SOLARIS_VERSION
-SYSROOT=${DEVKIT_ROOT}/sysroot
-SOLARIS_STUDIO_SUBDIR=SS${SOLARIS_STUDIO_VERSION}
-SOLARIS_STUDIO_DIR=${DEVKIT_ROOT}/${SOLARIS_STUDIO_SUBDIR}
-
-# Extract the publisher from the system
-if [ -z "${PUBLISHER_URI}" ]; then
- PUBLISHER_URI="$(pkg publisher solaris | grep URI | awk '{ print $3 }')"
-fi
-
-if [ ! -d $INSTALL_ROOT ]; then
- echo "Creating $INSTALL_ROOT and installing packages"
- pkg image-create $INSTALL_ROOT
- pkg -R $INSTALL_ROOT set-publisher -P -g ${PUBLISHER_URI} solaris
- sudo pkg -R $INSTALL_ROOT install --accept entire@$SOLARIS_ENTIRE_VERSION \
- system/install developer/gnu-binutils system/library/mmheap system/picl \
- developer/assembler system/library/freetype-2
-else
- echo "Skipping installing packages"
-fi
-
-if [ ! -d $SYSROOT ]; then
- echo "Copying from $INSTALL_ROOT to $SYSROOT"
- mkdir -p $SYSROOT
- cp -rH $INSTALL_ROOT/lib $SYSROOT/
- mkdir $SYSROOT/usr
- cp -rH $INSTALL_ROOT/usr/lib $SYSROOT/usr/
- cp -rH $INSTALL_ROOT/usr/include $SYSROOT/usr/
- pkg -R $INSTALL_ROOT list > $SYSROOT/pkg-list.txt
-else
- echo "Skipping copying to $SYSROOT"
-fi
-
-if [ ! -d $DEVKIT_ROOT/tools ]; then
- # Some of the tools in sysroot are needed in the OpenJDK build. We need
- # to copy them into a tools dir, including their specific libraries.
- mkdir -p $DEVKIT_ROOT/tools/usr/bin $DEVKIT_ROOT/tools/lib/sparcv9 \
- $DEVKIT_ROOT/tools/usr/gnu/bin $DEVKIT_ROOT/tools/usr/bin/sparcv9
- cp $INSTALL_ROOT/usr/bin/{as,ar,nm,strip,ld,pigz,ldd} \
- $DEVKIT_ROOT/tools/usr/bin/
- cp $INSTALL_ROOT/usr/sbin/dtrace $DEVKIT_ROOT/tools/usr/bin/
- cp $INSTALL_ROOT/usr/sbin/sparcv9/dtrace $DEVKIT_ROOT/tools/usr/bin/sparcv9/
- cp -rH $INSTALL_ROOT/usr/gnu/bin/* $DEVKIT_ROOT/tools/usr/gnu/bin/
- cp $INSTALL_ROOT/lib/sparcv9/{libelf.so*,libld.so*,liblddbg.so*} $DEVKIT_ROOT/tools/lib/sparcv9/
- for t in $(ls $DEVKIT_ROOT/tools/usr/gnu/bin); do
- if [ -f $DEVKIT_ROOT/tools/usr/gnu/bin/$t ]; then
- ln -s ../gnu/bin/$t $DEVKIT_ROOT/tools/usr/bin/g$t
- fi
- done
-else
- echo "Skipping copying to tools dir $DEVKIT_ROOT/tools"
-fi
-
-if [ ! -d $SOLARIS_STUDIO_DIR ]; then
- echo "Copying Solaris Studio from $SOLARIS_STUDIO_SRC"
- mkdir -p ${SOLARIS_STUDIO_DIR}
- cp -rH $SOLARIS_STUDIO_SRC/. ${SOLARIS_STUDIO_DIR}/
- # Solaris Studio 12.6 requires libmmheap.so.1 and libsunmath.so.1 to run, but
- # these libs are not installed by default on all Solaris systems.
- # Sneak them in from the sysroot to make it run OOTB on more systems.
- cp $SYSROOT/lib/libsunmath.so.1 $SOLARIS_STUDIO_DIR/lib/compilers/sys/
- cp $SYSROOT/lib/sparcv9/libsunmath.so.1 $SOLARIS_STUDIO_DIR/lib/compilers/sys/sparcv9/
- cp $SYSROOT/lib/libmmheap.so.1 $SOLARIS_STUDIO_DIR/lib/compilers/sys/
- cp $SYSROOT/lib/sparcv9/libmmheap.so.1 $SOLARIS_STUDIO_DIR/lib/compilers/sys/sparcv9/
-else
- echo "Skipping copying of Solaris Studio"
-fi
-
-# Create the devkit.info file
-echo Creating devkit.info
-INFO_FILE=$DEVKIT_ROOT/devkit.info
-rm -f $INFO_FILE
-echo "# This file describes to configure how to interpret the contents of this devkit" >> $INFO_FILE
-echo "DEVKIT_NAME=\"Solaris Studio $SOLARIS_STUDIO_VERSION - Solaris $SOLARIS_VERSION - $ARCH\"" >> $INFO_FILE
-echo "DEVKIT_TOOLCHAIN_PATH=\"\$DEVKIT_ROOT/$SOLARIS_STUDIO_SUBDIR/bin:\$DEVKIT_ROOT/bin\"" >> $INFO_FILE
-echo "DEVKIT_EXTRA_PATH=\"\$DEVKIT_ROOT/tools/usr/bin\"" >> $INFO_FILE
-echo "DEVKIT_SYSROOT=\"\$DEVKIT_ROOT/sysroot\"" >> $INFO_FILE
-
-if [ ! -e $BUNDLE ]; then
- GZIP=$(command -v pigz)
- if [ -z "$GZIP" ]; then
- GZIP="gzip"
- fi
- echo "Creating $BUNDLE from $DEVKIT_ROOT"
- (cd $DEVKIT_ROOT && tar cf - . | $GZIP - > "$BUNDLE")
-else
- echo "Skipping creation of $BUNDLE"
-fi
diff --git a/make/devkit/solaris11.1-package-list.txt b/make/devkit/solaris11.1-package-list.txt
deleted file mode 100644
index fa53559df25..00000000000
--- a/make/devkit/solaris11.1-package-list.txt
+++ /dev/null
@@ -1,157 +0,0 @@
-compress/bzip2@1.0.6-0.175.1.0.0.24.0
-consolidation/X/X-incorporation@0.5.11-0.175.1.21.0.3.1357
-consolidation/desktop/desktop-incorporation@0.5.11-0.175.1.21.0.4.0
-consolidation/install/install-incorporation@0.5.11-0.175.2.0.0.5.0
-consolidation/ips/ips-incorporation@0.5.11-0.175.1.20.0.3.0
-consolidation/l10n/l10n-incorporation@0.5.11-0.175.1.16.0.2.2
-consolidation/osnet/osnet-incorporation@0.5.11-0.175.1.21.0.4.2
-consolidation/sic_team/sic_team-incorporation@0.5.11-0.175.2.0.0.39.0
-consolidation/solaris_re/solaris_re-incorporation@0.5.11-0.175.2.4.0.4.0
-consolidation/sunpro/sunpro-incorporation@0.5.11-0.175.1.19.0.4.0
-crypto/ca-certificates@0.5.11-0.175.1.0.0.24.2
-database/berkeleydb-5@5.1.25-0.175.1.0.0.24.0
-database/mysql-51/library@5.1.37-0.175.1.10.0.5.0
-database/sqlite-3@3.7.14.1-0.175.1.10.0.4.0
-developer/base-developer-utilities@0.5.11-0.175.1.11.0.1.2
-developer/gnu-binutils@2.21.1-0.175.1.0.0.24.0
-developer/macro/cpp@0.5.11-0.175.1.19.0.4.0
-driver/management/bmc@0.5.11-0.175.1.0.0.24.2
-driver/management/ipmi@0.5.11-0.175.1.6.0.3.2
-driver/serial/usbser@0.5.11-0.175.1.0.0.24.2
-driver/storage/mpt@0.5.11-0.175.1.18.0.3.2
-image/library/libjpeg@6.0.2-0.175.0.0.0.0.0
-image/library/libpng@1.4.11-0.175.1.0.0.16.0
-image/library/libtiff@3.9.5-0.175.1.15.0.2.0
-library/apr-13@1.3.9-0.175.1.0.0.24.0
-library/apr-util-13@1.3.9-0.175.1.0.0.24.0
-library/apr-util-13/apr-ldap@1.3.9-0.175.1.0.0.24.0
-library/apr-util-13/dbd-mysql@1.3.9-0.175.1.0.0.24.0
-library/apr-util-13/dbd-sqlite@1.3.9-0.175.1.0.0.24.0
-library/database/gdbm@1.8.3-0.175.1.0.0.24.0
-library/expat@2.1.0-0.175.1.0.0.24.0
-library/libffi@3.0.9-0.175.0.0.0.0.0
-library/libidn@1.19-0.175.1.0.0.24.0
-library/libtecla@1.6.1-0.175.1.0.0.24.0
-library/libxml2@2.7.6-0.175.1.7.0.3.0
-library/libxslt@1.1.26-0.175.1.11.0.4.0
-library/ncurses@5.7-0.175.1.0.0.15.0
-library/nspr@4.9.5-0.175.2.0.0.39.0
-library/perl-5/sun-solaris-512@0.5.11-0.175.1.11.0.1.2
-library/print/cups-libs@1.4.5-0.175.1.8.0.3.0
-library/python-2/cherrypy@3.1.2-0.175.1.0.0.24.0
-library/python-2/cherrypy-26@3.1.2-0.175.1.0.0.24.0
-library/python-2/jsonrpclib@0.1.3-0.175.2.0.0.42.1
-library/python-2/jsonrpclib-26@0.1.3-0.175.2.0.0.42.1
-library/python-2/libxml2-26@2.7.6-0.175.1.7.0.3.0
-library/python-2/libxsl-26@1.1.26-0.175.1.11.0.4.0
-library/python-2/lxml@2.3.3-0.175.1.0.0.24.0
-library/python-2/lxml-26@2.3.3-0.175.1.0.0.24.0
-library/python-2/m2crypto@0.21.1-0.175.1.0.0.24.0
-library/python-2/m2crypto-26@0.21.1-0.175.1.0.0.24.0
-library/python-2/mako@0.4.1-0.175.1.0.0.24.0
-library/python-2/mako-26@0.4.1-0.175.1.0.0.24.0
-library/python-2/ply@3.1-0.175.1.0.0.24.0
-library/python-2/ply-26@3.1-0.175.1.0.0.24.0
-library/python-2/pybonjour@1.1.1-0.175.1.0.0.24.0
-library/python-2/pybonjour-26@1.1.1-0.175.1.0.0.24.0
-library/python-2/pycurl@7.19.0.1-0.175.1.0.0.24.0
-library/python-2/pycurl-26@7.19.0.1-0.175.1.0.0.24.0
-library/python-2/pyopenssl@0.11-0.175.1.0.0.24.0
-library/python-2/pyopenssl-26@0.11-0.175.1.0.0.24.0
-library/python-2/python-extra-26@2.6.4-0.175.1.0.0.15.0
-library/python-2/simplejson-26@2.1.2-0.175.1.7.0.4.0
-library/readline@5.2-0.175.1.0.0.24.0
-library/security/nss@4.14.3-0.175.2.0.0.39.0
-library/security/openssl@1.0.0.13-0.175.1.21.0.2.0
-library/security/trousers@0.3.6-0.175.1.0.0.24.0
-library/zlib@1.2.3-0.175.1.0.0.24.0
-media/cdrtools@3.0-0.175.1.21.0.4.0
-media/xorriso@0.6.0-0.175.1.0.0.24.0
-network/bridging@0.5.11-0.175.1.12.0.3.2
-package/pkg@0.5.11-0.175.1.20.0.3.0
-package/pkg/system-repository@0.5.11-0.175.1.9.0.1.0
-package/pkg/zones-proxy@0.5.11-0.175.1.0.0.24.0
-package/svr4@0.5.11-0.175.1.7.0.3.2
-print/cups@1.4.5-0.175.1.8.0.3.0
-release/name@0.5.11-0.175.2.4.0.4.0
-runtime/perl-512@5.12.5-0.175.1.8.0.4.0
-runtime/python-26@2.6.8-0.175.1.17.0.4.0
-service/network/dns/mdns@0.5.11-0.175.1.0.0.24.2
-service/network/slp@0.5.11-0.175.1.0.0.24.2
-service/security/gss@0.5.11-0.175.1.0.0.24.2
-service/security/kerberos-5@0.5.11-0.175.1.18.0.2.2
-shell/bash@4.1.9-0.175.1.13.0.1.0
-shell/ksh93@93.21.0.20110208-0.175.1.19.0.2.0
-system/boot-environment-utilities@0.5.11-0.175.1.9.0.1.2
-system/boot/grub@1.99-0.175.1.14.0.2.2
-system/boot/wanboot@0.5.11-0.175.1.0.0.24.2
-system/core-os@0.5.11-0.175.1.20.0.4.2
-system/data/keyboard/keytables@0.5.11-0.175.1.0.0.24.2
-system/data/terminfo/terminfo-core@0.5.11-0.175.1.14.0.3.2
-system/data/timezone@0.5.11-0.175.2.5.0.2.0
-system/device-administration@0.5.11-0.175.1.9.0.2.2
-system/dtrace@0.5.11-0.175.1.20.0.4.2
-system/dynamic-reconfiguration@0.5.11-0.175.1.13.0.2.2
-system/fault-management@0.5.11-0.175.1.18.0.4.2
-system/file-system/hsfs@0.5.11-0.175.1.0.0.24.2
-system/file-system/pcfs@0.5.11-0.175.1.0.0.24.2
-system/file-system/ufs@0.5.11-0.175.1.18.0.3.2
-system/file-system/zfs@0.5.11-0.175.1.21.0.3.2
-system/header@0.5.11-0.175.1.20.0.4.2
-system/install@0.5.11-0.175.1.0.0.24.1736
-system/install/auto-install/auto-install-common@0.5.11-0.175.1.18.0.3.1736
-system/install/configuration@0.5.11-0.175.1.10.0.3.1736
-system/install/locale@0.5.11-0.175.1.0.0.23.1134
-system/io/infiniband@0.5.11-0.175.1.20.0.4.2
-system/io/ultra-wideband@0.5.11-0.175.1.0.0.24.2
-system/io/usb@0.5.11-0.175.1.19.0.2.2
-system/kernel@0.5.11-0.175.1.21.0.4.2
-system/kernel/cpu-counters@0.5.11-0.175.1.17.0.1.2
-system/kernel/platform@0.5.11-0.175.1.21.0.4.2
-system/keyboard/keyboard-utilities@0.5.11-0.175.1.0.0.24.2
-system/library@0.5.11-0.175.1.20.0.3.2
-system/library/boot-management@0.5.11-0.175.1.19.0.1.2
-system/library/c++-runtime@0.5.11-0.175.1.19.0.4.0
-system/library/freetype-2@2.4.11-0.175.1.18.0.1.1350
-system/library/gcc-3-runtime@3.4.3-0.175.1.0.0.24.0
-system/library/iconv/utf-8@0.5.11-0.175.1.9.0.1.1150
-system/library/install@0.5.11-0.175.1.18.0.3.1736
-system/library/libdbus@1.2.28-0.175.1.16.0.2.0
-system/library/math@0.5.11-0.175.1.19.0.4.0
-system/library/mmheap@0.5.11-0.175.1.19.0.4.0
-system/library/security/gss@0.5.11-0.175.1.18.0.3.2
-system/library/security/gss/diffie-hellman@0.5.11-0.175.1.0.0.24.2
-system/library/security/gss/spnego@0.5.11-0.175.1.16.0.1.2
-system/library/security/libsasl@0.5.11-0.175.1.0.0.24.2
-system/library/storage/libdiskmgt@0.5.11-0.175.1.5.0.3.2
-system/library/storage/scsi-plugins@0.5.11-0.175.1.0.0.24.2
-system/library/storage/snia-ima@0.5.11-0.175.1.0.0.24.2
-system/library/storage/suri@0.5.11-0.175.1.0.0.24.2
-system/linker@0.5.11-0.175.1.20.0.1.2
-system/network@0.5.11-0.175.1.20.0.3.2
-system/picl@0.5.11-0.175.1.17.0.3.2
-system/resource-mgmt/resource-pools@0.5.11-0.175.1.0.0.24.2
-system/storage/iscsi/iscsi-initiator@0.5.11-0.175.1.19.0.3.2
-system/storage/iscsi/iscsi-iser@0.5.11-0.175.1.20.0.3.2
-system/system-events@0.5.11-0.175.1.0.0.24.2
-system/xopen/xcu4@0.5.11-0.175.1.13.0.4.2
-system/zones@0.5.11-0.175.1.17.0.4.2
-system/zones/brand/brand-solaris@0.5.11-0.175.1.17.0.4.2
-text/spelling-utilities@0.5.11-0.175.1.0.0.24.2
-web/curl@7.21.2-0.175.1.18.0.3.0
-web/server/apache-22@2.2.27-0.175.1.19.0.4.0
-web/server/apache-22/module/apache-wsgi-26@3.3-0.175.1.0.0.24.0
-x11/header/x11-protocols@7.7-0.175.1.0.0.24.1317
-x11/library/libice@1.0.8-0.175.1.0.0.24.1317
-x11/library/libpthread-stubs@0.3-0.175.1.0.0.24.1317
-x11/library/libsm@1.2.1-0.175.1.0.0.24.1317
-x11/library/libx11@1.5.0-0.175.1.8.0.4.1336
-x11/library/libxau@1.0.7-0.175.1.0.0.24.1317
-x11/library/libxcb@1.8.1-0.175.1.8.0.3.1332
-x11/library/libxdmcp@1.1.1-0.175.1.0.0.24.1317
-x11/library/libxevie@1.0.3-0.175.1.0.0.24.1317
-x11/library/libxext@1.3.1-0.175.1.8.0.3.1332
-x11/library/libxrender@0.9.7-0.175.1.8.0.3.1332
-x11/library/libxscrnsaver@1.2.2-0.175.1.0.0.24.1317
-x11/library/libxtst@1.2.1-0.175.1.8.0.3.1332
-x11/library/toolkit/libxt@1.1.3-0.175.1.8.0.3.1332
diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk
index d302a3df655..0947133c16e 100644
--- a/make/hotspot/gensrc/GensrcAdlc.gmk
+++ b/make/hotspot/gensrc/GensrcAdlc.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -36,10 +36,6 @@ ifeq ($(call check-jvm-feature, compiler2), true)
# NOTE: No optimization or debug flags set here
ifeq ($(call isBuildOs, linux), true)
ADLC_CFLAGS := -fno-exceptions -DLINUX
- else ifeq ($(call isBuildOs, solaris), true)
- ADLC_LDFLAGS := -m64
- ADLC_CFLAGS := -m64
- ADLC_CFLAGS_WARNINGS := +w
else ifeq ($(call isBuildOs, aix), true)
ADLC_LDFLAGS := -q64
ADLC_CFLAGS := -qnortti -qeh -q64 -DAIX
@@ -88,8 +84,6 @@ ifeq ($(call check-jvm-feature, compiler2), true)
# ADLC flags depending on target OS
ifeq ($(call isTargetOs, linux), true)
ADLCFLAGS += -DLINUX=1 -D_GNU_SOURCE=1
- else ifeq ($(call isTargetOs, solaris), true)
- ADLCFLAGS += -DSOLARIS=1 -DSPARC_WORKS=1
else ifeq ($(call isTargetOs, aix), true)
ADLCFLAGS += -DAIX=1
else ifeq ($(call isTargetOs, macosx), true)
diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk
index 2a54a6391fa..0cc0ff11093 100644
--- a/make/hotspot/gensrc/GensrcDtrace.gmk
+++ b/make/hotspot/gensrc/GensrcDtrace.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,7 @@
ifeq ($(call check-jvm-feature, dtrace), true)
- ifeq ($(call isTargetOs, solaris), true)
- DTRACE_FLAGS := -64
- DTRACE_CPP_FLAGS := -D_LP64
- else ifeq ($(call isTargetOs, macosx), true)
+ ifeq ($(call isTargetOs, macosx), true)
DTRACE_CPP_FLAGS := -D_LP64 -x c
else ifeq ($(call isTargetOs, linux), true)
DTRACE_CPP_FLAGS := -x c
@@ -54,61 +51,4 @@ ifeq ($(call check-jvm-feature, dtrace), true)
TARGETS += $(patsubst $(DTRACE_SOURCE_DIR)/%.d, \
$(DTRACE_GENSRC_DIR)/%.h, $(wildcard $(DTRACE_SOURCE_DIR)/*.d))
- ifeq ($(call isTargetOs, solaris), true)
- ############################################################################
- # First we need to generate the dtraceGenOffsets tool. When run, this will
- # produce two header files and a C++ file. Note that generateJvmOffsets.cpp
- # is using the same JVM_CFLAGS as libjvm.so.
-
- # Include support files that will setup JVM compiler flags.
- include lib/JvmFeatures.gmk
- include lib/JvmFlags.gmk
-
- # We cannot compile until the JVMTI and JFR gensrc has finished.
- # JFR_FILES is defined in GensrcJfr.gmk.
- JVMTI_H := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h
-
- $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \
- NAME := dtraceGenOffsets, \
- TYPE := EXECUTABLE, \
- SRC := $(TOPDIR)/make/hotspot/src/native/dtrace, \
- TOOLCHAIN := $(TOOLCHAIN_BUILD), \
- LDFLAGS := -m64, \
- CFLAGS := -m64 $(JVM_CFLAGS), \
- DISABLED_WARNINGS_solstudio := hidef w_novirtualdescr unknownpragma \
- doubunder nokeyworddefine wunreachable, \
- EXTRA_DEPS := $(JVMTI_H) $(JFR_FILES), \
- OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \
- OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \
- ))
-
- DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET)
-
- # Argument 1: Output filename
- # Argument 2: dtrace-gen-offset tool command line option
- define SetupDtraceOffsetsGeneration
- $$(eval $$(call SetupExecute, dtrace_offset_$$(strip $2), \
- INFO := Generating dtrace $2 file, \
- DEPS := $$(BUILD_DTRACE_GEN_OFFSETS), \
- OUTPUT_FILE := $1, \
- COMMAND := ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $1 ), \
- ))
-
- TARGETS += $$(dtrace_offset_$$(strip $2)_TARGET)
- endef
-
- JVM_OFFSETS_H := $(DTRACE_GENSRC_DIR)/JvmOffsets.h
- JVM_OFFSETS_CPP := $(DTRACE_GENSRC_DIR)/JvmOffsets.cpp
- JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
-
- ############################################################################
- # Run the dtrace-gen-offset tool to generate these three files.
- # The generated JvmOffsets.cpp is compiled with the rest of libjvm.
- # The header files are used by libjvm_db and jhelper.d, respectively.
-
- $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header))
- $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index))
- $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table))
- endif
-
endif
diff --git a/make/hotspot/lib/CompileDtraceLibraries.gmk b/make/hotspot/lib/CompileDtraceLibraries.gmk
deleted file mode 100644
index 7f49a8eb9fa..00000000000
--- a/make/hotspot/lib/CompileDtraceLibraries.gmk
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-ifeq ($(call check-jvm-feature, dtrace), true)
- ifeq ($(call isTargetOs, solaris), true)
- JNI_INCLUDE_FLAGS := \
- -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base \
- -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base/$(OPENJDK_TARGET_OS_INCLUDE_SUBDIR) \
- #
-
- ############################################################################
- # Build the stand-alone dtrace libraries.
-
- LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace
- $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \
- NAME := jvm_dtrace, \
- OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
- SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_dtrace, \
- CFLAGS := $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \
- LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
- LIBS := $(LIBDL) -lthread -ldoor, \
- OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \
- ))
-
- # Note that libjvm_db.c has tests for COMPILER2, but this was never set by
- # the old build.
- LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db
- $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \
- NAME := jvm_db, \
- OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
- SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_db, \
- CFLAGS := -I$(DTRACE_GENSRC_DIR) $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \
- LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
- OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \
- ))
-
- TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB)
-
- endif
-endif
diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk
index 7932c2d9097..238956ab45a 100644
--- a/make/hotspot/lib/CompileGtest.gmk
+++ b/make/hotspot/lib/CompileGtest.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -76,17 +76,13 @@ $(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \
-I$(GTEST_FRAMEWORK_SRC)/googlemock/include \
$(addprefix -I,$(GTEST_TEST_SRC)), \
CFLAGS_windows := -EHsc, \
- CFLAGS_solaris := -DGTEST_HAS_EXCEPTIONS=0 -library=stlport4, \
CFLAGS_macosx := -DGTEST_OS_MAC=1, \
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \
undef, \
DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang) \
undef switch format-nonliteral tautological-undefined-compare \
self-assign-overloaded, \
- DISABLED_WARNINGS_solstudio := $(DISABLED_WARNINGS_solstudio) \
- identexpected, \
LDFLAGS := $(JVM_LDFLAGS), \
- LDFLAGS_solaris := -library=stlport4 $(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(JVM_LIBS), \
OPTIMIZATION := $(JVM_OPTIMIZATION), \
MAPFILE := $(GTEST_JVM_MAPFILE), \
@@ -116,7 +112,6 @@ $(eval $(call SetupNativeCompilation, BUILD_GTEST_LAUNCHER, \
-I$(GTEST_FRAMEWORK_SRC)/googlemock/include, \
LDFLAGS := $(LDFLAGS_JDKEXE), \
LDFLAGS_unix := -L$(JVM_OUTPUTDIR)/gtest $(call SET_SHARED_LIBRARY_ORIGIN), \
- LDFLAGS_solaris := -library=stlport4, \
LIBS_linux := $(LIBCXX), \
LIBS_unix := -ljvm, \
LIBS_windows := $(JVM_OUTPUTDIR)/gtest/objs/jvm.lib, \
diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk
index c7b820d949b..0cfc5deb62e 100644
--- a/make/hotspot/lib/CompileJvm.gmk
+++ b/make/hotspot/lib/CompileJvm.gmk
@@ -29,9 +29,6 @@ include lib/JvmFeatures.gmk
include lib/JvmOverrideFiles.gmk
include lib/JvmFlags.gmk
-# Include support files that will setup DTRACE_EXTRA_OBJECT_FILES.
-include lib/JvmDtraceObjects.gmk
-
################################################################################
# Setup compilation of the main Hotspot native library (libjvm).
@@ -60,8 +57,6 @@ JVM_EXCLUDES += adlc
# Needed by abstract_vm_version.cpp
ifeq ($(call isTargetCpu, x86_64), true)
OPENJDK_TARGET_CPU_VM_VERSION := amd64
-else ifeq ($(call isTargetCpu, sparcv9), true)
- OPENJDK_TARGET_CPU_VM_VERSION := sparc
else
OPENJDK_TARGET_CPU_VM_VERSION := $(OPENJDK_TARGET_CPU)
endif
@@ -97,10 +92,6 @@ DISABLED_WARNINGS_clang := tautological-compare \
delete-non-virtual-dtor missing-braces char-subscripts \
ignored-qualifiers missing-field-initializers mismatched-tags
-DISABLED_WARNINGS_solstudio := labelnotused hidef w_novirtualdescr inlafteruse \
- unknownpragma doubunder w_enumnotused w_toomanyenumnotused \
- wvarhidenmem wunreachable wnoretvalue notemsource
-
DISABLED_WARNINGS_xlc := tautological-compare shift-negative-value
DISABLED_WARNINGS_microsoft :=
@@ -134,29 +125,6 @@ else ifeq ($(call isTargetCpu, x86_64), true)
JVM_EXCLUDE_PATTERNS += x86_32
endif
-# Inline assembly for solaris
-ifeq ($(call isTargetOs, solaris), true)
- ifeq ($(call isTargetCpu, x86_64), true)
- JVM_CFLAGS += $(TOPDIR)/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il
- else ifeq ($(call isTargetCpu, sparcv9), true)
- JVM_CFLAGS += $(TOPDIR)/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il
- endif
- # Exclude warnings in devstudio 12.6
- ifeq ($(CC_VERSION_NUMBER), 5.15)
- DISABLED_WARNINGS_solstudio += SEC_ARR_OUTSIDE_BOUND_READ \
- SEC_ARR_OUTSIDE_BOUND_WRITE
- endif
-endif
-
-ifeq ($(call And, $(call isTargetOs, solaris) $(call isTargetCpu, sparcv9)), true)
- ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), false)
- # NOTE: In the old build, we weirdly enough set -g/-g0 always, regardless
- # of if debug symbols were needed. Without it, compilation fails on
- # sparc! :-(
- JVM_CFLAGS += -g0
- endif
-endif
-
ifeq ($(call isTargetOs, windows), true)
ifeq ($(call isTargetCpuBits, 64), true)
RC_DESC := 64-Bit$(SPACE)
@@ -185,13 +153,11 @@ $(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \
EXCLUDES := $(JVM_EXCLUDES), \
EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \
EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \
- EXTRA_OBJECT_FILES := $(DTRACE_EXTRA_OBJECT_FILES), \
CFLAGS := $(JVM_CFLAGS), \
abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc), \
DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang), \
- DISABLED_WARNINGS_solstudio := $(DISABLED_WARNINGS_solstudio), \
DISABLED_WARNINGS_xlc := $(DISABLED_WARNINGS_xlc), \
DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft), \
ASFLAGS := $(JVM_ASFLAGS), \
@@ -275,30 +241,20 @@ TARGETS += $(BUILD_LIBJVM)
# one) then the global definition will be used, triggering this check.
ifneq ($(GENERATE_COMPILE_COMMANDS_ONLY), true)
- ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang solstudio), )
+ ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), )
DEMANGLED_REGEXP := [^:]operator (new|delete)
# Running c++filt to find offending symbols in all files is too expensive,
- # especially on Solaris, so use mangled names when looking for symbols.
+ # so use mangled names when looking for symbols.
# Save the demangling for when something is actually found.
- ifeq ($(TOOLCHAIN_TYPE), solstudio)
- MANGLED_SYMS := \
- __1c2n6FL_pv_ \
- __1c2N6FL_pv_ \
- __1c2k6Fpv_v_ \
- __1c2K6Fpv_v_ \
- #
- UNDEF_PATTERN := UNDEF
- else
- MANGLED_SYMS := \
- _ZdaPv \
- _ZdlPv \
- _Znam \
- _Znwm \
- #
- UNDEF_PATTERN := ' U '
- endif
+ MANGLED_SYMS := \
+ _ZdaPv \
+ _ZdlPv \
+ _Znam \
+ _Znwm \
+ #
+ UNDEF_PATTERN := ' U '
define SetupOperatorNewDeleteCheck
$1.op_check: $1
diff --git a/make/hotspot/lib/CompileLibraries.gmk b/make/hotspot/lib/CompileLibraries.gmk
index 9b04c406421..9f68d7033ad 100644
--- a/make/hotspot/lib/CompileLibraries.gmk
+++ b/make/hotspot/lib/CompileLibraries.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ include NativeCompilation.gmk
include HotspotCommon.gmk
include lib/CompileJvm.gmk
-include lib/CompileDtraceLibraries.gmk
ifeq ($(BUILD_GTEST), true)
include lib/CompileGtest.gmk
diff --git a/make/hotspot/lib/JvmDtraceObjects.gmk b/make/hotspot/lib/JvmDtraceObjects.gmk
deleted file mode 100644
index f2bfa272d03..00000000000
--- a/make/hotspot/lib/JvmDtraceObjects.gmk
+++ /dev/null
@@ -1,135 +0,0 @@
-#
-# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-ifeq ($(call check-jvm-feature, dtrace), true)
- ifeq ($(call isTargetOs, solaris), true)
-
- ############################################################################
- # Integrate with libjvm. Here we generate two object files which are
- # linked with libjvm.so. This step is complicated from a dependency
- # perspective. We add these two files to the linking of libjvm using
- # EXTRA_OBJECT_FILES, but they need to be created outside the call to
- # SetupNativeCompilation. Also, one of the files is dependent on compiled
- # object files from the libjvm compilation, so this generation must happen
- # as a part of the libjvm compilation.
-
- DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o
- DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o
-
- DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ)
-
- ############################################################################
- # Generate DTRACE_OBJ which is linked with libjvm.so. It depends on a set of
- # object files from the compilation.
-
- # Concatenate all *.d files into a single file
- DTRACE_SOURCE_FILES := $(addprefix $(TOPDIR)/src/hotspot/os/posix/dtrace/, \
- hotspot_jni.d \
- hotspot.d \
- hs_private.d \
- )
-
- # *.d in the objs dir is used for generated make dependency files, so use
- # *.dt for dtrace files to avoid clashes.
- $(JVM_OUTPUTDIR)/objs/dtrace.dt: $(DTRACE_SOURCE_FILES)
- $(call LogInfo, Generating $(@F))
- $(call MakeDir, $(@D))
- $(CAT) $^ > $@
-
- DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \
- ciEnv.o \
- classLoadingService.o \
- compileBroker.o \
- gcVMOperations.o \
- hashtable.o \
- instanceKlass.o \
- java.o \
- jni.o \
- jvm.o \
- memoryManager.o \
- nmethod.o \
- objectMonitor.o \
- runtimeService.o \
- sharedRuntime.o \
- synchronizer.o \
- thread.o \
- unsafe.o \
- vmThread.o \
- )
-
- ifeq ($(call check-jvm-feature, parallelgc), true)
- DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
- psVMOperations.o \
- )
- endif
-
- DTRACE_FLAGS := -64 -G
- DTRACE_CPP_FLAGS := -D_LP64
-
- # Make sure we run our selected compiler for preprocessing instead of letting
- # the dtrace tool pick it on it's own.
- $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.dt $(DTRACE_INSTRUMENTED_OBJS)
- $(call LogInfo, Generating $(@F) from $( $(DTRACE_SUPPORT_DIR)/$(@F).dt))
- $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \
- -s $(DTRACE_SUPPORT_DIR)/$(@F).dt $(sort $(DTRACE_INSTRUMENTED_OBJS)))
-
- ############################################################################
- # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so.
-
- JHELPER_DTRACE_SRC := $(TOPDIR)/src/hotspot/os/solaris/dtrace/jhelper.d
-
- # jhelper.d includes JvmOffsetsIndex.h which was created by the gensrc step.
- DTRACE_GENSRC_DIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/dtracefiles
- JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
-
- # Unfortunately dtrace generates incorrect types for some symbols in
- # dtrace_jhelper.o, resulting in "warning: symbol X has differing types"
- # See JDK-6890703 for details.
- # We work around this by fixing the types for these symbols using elfedit,
- # after dtrace has generated the .o file.
- GetElfeditCommands = \
- $(foreach symbol, \
- $(shell $(GREP) ^extern $(JHELPER_DTRACE_SRC) | $(AWK) '{ gsub(";","") ; print $$3 }'), \
- -e 'sym:st_type $(symbol) 1')
-
- # Make sure we run our selected compiler for preprocessing instead of letting
- # the dtrace tool pick it on it's own.
- $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H)
- $(call LogInfo, Running dtrace for $( $(DTRACE_SUPPORT_DIR)/$(@F).dt))
- $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \
- -s $(DTRACE_SUPPORT_DIR)/$(@F).dt)
- ifeq ($(call isTargetCpuArch, sparc), true)
- $(call ExecuteWithLog, $@.elfedit, $(ELFEDIT) $(call GetElfeditCommands) $@)
- endif
-
- endif
-endif
diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk
index 22772493f23..6a525cfa6db 100644
--- a/make/hotspot/lib/JvmFeatures.gmk
+++ b/make/hotspot/lib/JvmFeatures.gmk
@@ -50,9 +50,6 @@ ifeq ($(call check-jvm-feature, zero), true)
ifeq ($(ENABLE_LIBFFI_BUNDLING), true)
JVM_LDFLAGS_FEATURES += $(call SET_EXECUTABLE_ORIGIN,/..)
endif
- ifeq ($(call isTargetCpu, sparcv9), true)
- BUILD_LIBJVM_EXTRA_FILES := $(TOPDIR)/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp
- endif
endif
ifeq ($(JVM_VARIANT), custom)
diff --git a/make/hotspot/lib/JvmMapfile.gmk b/make/hotspot/lib/JvmMapfile.gmk
index f750ae8d20a..c75eecd3ced 100644
--- a/make/hotspot/lib/JvmMapfile.gmk
+++ b/make/hotspot/lib/JvmMapfile.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -48,18 +48,6 @@ ifneq ($(findstring debug, $(DEBUG_LEVEL)), )
endif
endif
-ifeq ($(call isTargetOs, solaris), true)
- ifeq ($(call check-jvm-feature, dtrace), true)
- # Additional mapfiles that are only used when dtrace is enabled
- ifeq ($(call check-jvm-feature, compiler2), true)
- # This also covers the case of compiler1+compiler2.
- SYMBOLS_SRC += $(TOPDIR)/make/hotspot/symbols/symbols-solaris-dtrace-compiler2
- else ifeq ($(call check-jvm-feature, compiler1), true)
- SYMBOLS_SRC += $(TOPDIR)/make/hotspot/symbols/symbols-solaris-dtrace-compiler1
- endif
- endif
-endif
-
################################################################################
# Create a dynamic list of symbols from the built object files. This is highly
# platform dependent.
@@ -76,20 +64,6 @@ ifeq ($(call isTargetOs, linux), true)
if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \
}'
-else ifeq ($(call isTargetOs, solaris), true)
- DUMP_SYMBOLS_CMD := $(NM) -p *.o
- ifneq ($(FILTER_SYMBOLS_PATTERN), )
- FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|
- endif
- FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)^__1c.*__vtbl_$$|^gHotSpotVM
- FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^UseSharedSpaces$$
- FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^__1cJArgumentsRSharedArchivePath_$$
- FILTER_SYMBOLS_AWK_SCRIPT := \
- '{ \
- if ($$2 == "U") next; \
- if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \
- }'
-
else ifeq ($(call isTargetOs, macosx), true)
# nm on macosx prints out "warning: nm: no name list" to stderr for
# files without symbols. Hide this, even at the expense of hiding real errors.
diff --git a/make/hotspot/lib/JvmOverrideFiles.gmk b/make/hotspot/lib/JvmOverrideFiles.gmk
index ea4c84371f8..f606c99c812 100644
--- a/make/hotspot/lib/JvmOverrideFiles.gmk
+++ b/make/hotspot/lib/JvmOverrideFiles.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -83,52 +83,6 @@ ifeq ($(call isTargetOs, linux), true)
$(foreach s, $(NONPIC_SRC), $(eval BUILD_LIBJVM_$(notdir $s)_CXXFLAGS := -fno-PIC))
endif
-else ifeq ($(call isTargetOs, solaris), true)
- ifneq ($(DEBUG_LEVEL), slowdebug)
- # dev studio 12.6 workaround
- BUILD_LIBJVM_arguments.cpp_OPTIMIZATION := LOW
- # Workaround for a bug in dtrace. If ciEnv::post_compiled_method_load_event()
- # is inlined, the resulting dtrace object file needs a reference to this
- # function, whose symbol name is too long for dtrace. So disable inlining
- # for this method for now. (fix this when dtrace bug 6258412 is fixed)
- BUILD_LIBJVM_ciEnv.cpp_CXXFLAGS := \
- -xinline=no%__1cFciEnvbFpost_compiled_method_load_event6MpnHnmethod__v_
- # dtrace cannot handle tail call optimization (6672627, 6693876)
- BUILD_LIBJVM_jni.cpp_CXXFLAGS := -Qoption ube -O~yz
- BUILD_LIBJVM_stubGenerator_$(HOTSPOT_TARGET_CPU).cpp_CXXFLAGS := -xspace
-
- ifeq ($(call isTargetCpu, x86_64), true)
- # Temporary until SS10 C++ compiler is fixed
- BUILD_LIBJVM_generateOptoStub.cpp_CXXFLAGS := -xO2
- # Temporary util SS12u1 C++ compiler is fixed
- BUILD_LIBJVM_c1_LinearScan.cpp_CXXFLAGS := -xO2
- endif
- endif
-
- # Need extra inlining to get oop_ps_push_contents functions to perform well enough.
- ifeq ($(DEBUG_LEVEL),release)
- BUILD_LIBJVM_psPromotionManager.cpp_CXXFLAGS := -W2,-Ainline:inc=1000
- endif
-
- ifeq ($(DEBUG_LEVEL), fastdebug)
- # this hangs in iropt now (7113504)
- BUILD_LIBJVM_compileBroker.cpp_CXXFLAGS := -xO2
-
- # Frame size > 100k if we allow inlining via -g0!
- BUILD_LIBJVM_bytecodeInterpreter.cpp_CXXFLAGS := +d
- BUILD_LIBJVM_bytecodeInterpreterWithChecks.cpp_CXXFLAGS := +d
-
- ifeq ($(call isTargetCpuArch, x86), true)
- # ube explodes on x86
- BUILD_LIBJVM_bytecodeInterpreter.cpp_CXXFLAGS += -xO1
- BUILD_LIBJVM_bytecodeInterpreterWithChecks.cpp_CXXFLAGS += -xO1
- endif
-
- endif
-
- # Workaround for jvmciCompilerToVM.cpp long compilation time
- BUILD_LIBJVM_jvmciCompilerToVMInit.cpp_OPTIMIZATION := NONE
-
else ifeq ($(call isTargetOs, macosx), true)
# The copied fdlibm routines in these files must not be optimized
BUILD_LIBJVM_sharedRuntimeTrig.cpp_CXXFLAGS := $(FDLIBM_CFLAGS) $(LIBJVM_FDLIBM_COPY_OPT_FLAG)
diff --git a/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp b/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp
deleted file mode 100644
index c0ace26b684..00000000000
--- a/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-/*
- * This is to provide sanity check in jhelper.d which compares SCCS
- * versions of generateJvmOffsets.cpp used to create and extract
- * contents of __JvmOffsets[] table.
- * The __JvmOffsets[] table is located in generated JvmOffsets.cpp.
- *
- * GENOFFS_SCCS_VER 34
- */
-
-#include
-#include
-
-/* A workaround for private and protected fields */
-#define private public
-#define protected public
-
-#include
-#include "gc/shared/collectedHeap.hpp"
-#include "memory/heap.hpp"
-#include "oops/compressedOops.hpp"
-#include "runtime/vmStructs.hpp"
-
-typedef enum GEN_variant {
- GEN_OFFSET = 0,
- GEN_INDEX = 1,
- GEN_TABLE = 2
-} GEN_variant;
-
-#ifdef COMPILER1
-#ifdef ASSERT
-
-/*
- * To avoid the most part of potential link errors
- * we link this program with -z nodefs .
- *
- * But for 'debug1' and 'fastdebug1' we still have to provide
- * a particular workaround for the following symbols below.
- * It will be good to find out a generic way in the future.
- */
-
-#pragma weak tty
-
-#if defined(i386) || defined(__i386) || defined(__amd64)
-#pragma weak noreg
-#endif /* i386 */
-
-LIR_Opr LIR_OprFact::illegalOpr = (LIR_Opr) 0;
-
-address StubRoutines::_call_stub_return_address = NULL;
-
-StubQueue* AbstractInterpreter::_code = NULL;
-
-#endif /* ASSERT */
-#endif /* COMPILER1 */
-
-#define GEN_OFFS_NAME(Type,Name,OutputType) \
- switch(gen_variant) { \
- case GEN_OFFSET: \
- printf("#define OFFSET_%-33s %ld\n", \
- #OutputType #Name, offset_of(Type, Name)); \
- break; \
- case GEN_INDEX: \
- printf("#define IDX_OFFSET_%-33s %d\n", \
- #OutputType #Name, index++); \
- break; \
- case GEN_TABLE: \
- printf("\tOFFSET_%s,\n", #OutputType #Name); \
- break; \
- }
-
-#define GEN_OFFS(Type,Name) \
- GEN_OFFS_NAME(Type,Name,Type)
-
-#define GEN_SIZE(Type) \
- switch(gen_variant) { \
- case GEN_OFFSET: \
- printf("#define SIZE_%-35s %ld\n", \
- #Type, sizeof(Type)); \
- break; \
- case GEN_INDEX: \
- printf("#define IDX_SIZE_%-35s %d\n", \
- #Type, index++); \
- break; \
- case GEN_TABLE: \
- printf("\tSIZE_%s,\n", #Type); \
- break; \
- }
-
-#define GEN_VALUE(String,Value) \
- switch(gen_variant) { \
- case GEN_OFFSET: \
- printf("#define %-40s %d\n", #String, Value); \
- break; \
- case GEN_INDEX: \
- printf("#define IDX_%-40s %d\n", #String, index++); \
- break; \
- case GEN_TABLE: \
- printf("\t" #String ",\n"); \
- break; \
- }
-
-void gen_prologue(GEN_variant gen_variant) {
- const char *suffix = "Undefined-Suffix";
-
- switch(gen_variant) {
- case GEN_OFFSET: suffix = ".h"; break;
- case GEN_INDEX: suffix = "Index.h"; break;
- case GEN_TABLE: suffix = ".cpp"; break;
- }
-
- printf("/*\n");
- printf(" * JvmOffsets%s !!!DO NOT EDIT!!! \n", suffix);
- printf(" * The generateJvmOffsets program generates this file!\n");
- printf(" */\n\n");
- switch(gen_variant) {
-
- case GEN_OFFSET:
- case GEN_INDEX:
- break;
-
- case GEN_TABLE:
- printf("#include \"JvmOffsets.h\"\n");
- printf("\n");
- printf("int __JvmOffsets[] = {\n");
- break;
- }
-}
-
-void gen_epilogue(GEN_variant gen_variant) {
- if (gen_variant != GEN_TABLE) {
- return;
- }
- printf("};\n\n");
- return;
-}
-
-int generateJvmOffsets(GEN_variant gen_variant) {
- int index = 0; /* It is used to generate JvmOffsetsIndex.h */
- int pointer_size = sizeof(void *);
- int data_model = (pointer_size == 4) ? PR_MODEL_ILP32 : PR_MODEL_LP64;
-
- gen_prologue(gen_variant);
-
- GEN_VALUE(DATA_MODEL, data_model);
- GEN_VALUE(POINTER_SIZE, pointer_size);
-#if defined(TIERED)
- GEN_VALUE(COMPILER, 3);
-#elif COMPILER1
- GEN_VALUE(COMPILER, 1);
-#elif COMPILER2
- GEN_VALUE(COMPILER, 2);
-#else
- GEN_VALUE(COMPILER, 0);
-#endif // COMPILER1 && COMPILER2
- printf("\n");
-
- GEN_OFFS(CollectedHeap, _reserved);
- GEN_OFFS(MemRegion, _start);
- GEN_OFFS(MemRegion, _word_size);
- GEN_SIZE(HeapWord);
- printf("\n");
-
- GEN_OFFS(VMStructEntry, typeName);
- GEN_OFFS(VMStructEntry, fieldName);
- GEN_OFFS(VMStructEntry, address);
- GEN_SIZE(VMStructEntry);
- printf("\n");
-
- GEN_VALUE(MAX_METHOD_CODE_SIZE, max_method_code_size);
-#if defined(sparc) || defined(__sparc)
- GEN_VALUE(OFFSET_interpreter_frame_method, 2 * pointer_size); /* L2 in saved window */
- GEN_VALUE(OFFSET_interpreter_frame_sender_sp, 13 * pointer_size); /* I5 in saved window */
- // Fake value for consistency. It is not going to be used.
- GEN_VALUE(OFFSET_interpreter_frame_bcp_offset, 0xFFFF);
-#elif defined(i386) || defined(__i386) || defined(__amd64)
- GEN_VALUE(OFFSET_interpreter_frame_sender_sp, -1 * pointer_size);
- GEN_VALUE(OFFSET_interpreter_frame_method, -3 * pointer_size);
- GEN_VALUE(OFFSET_interpreter_frame_bcp_offset, -7 * pointer_size);
-#endif
-
- GEN_OFFS(Klass, _name);
- GEN_OFFS(ConstantPool, _pool_holder);
- printf("\n");
-
- GEN_VALUE(OFFSET_HeapBlockHeader_used, (int) offset_of(HeapBlock::Header, _used));
- GEN_OFFS(oopDesc, _metadata);
- printf("\n");
-
- GEN_VALUE(AccessFlags_NATIVE, JVM_ACC_NATIVE);
- GEN_VALUE(ConstMethod_has_linenumber_table, ConstMethod::_has_linenumber_table);
- GEN_OFFS(AccessFlags, _flags);
- GEN_OFFS(Symbol, _length);
- GEN_OFFS(Symbol, _body);
- printf("\n");
-
- GEN_OFFS(Method, _constMethod);
- GEN_OFFS(Method, _access_flags);
- printf("\n");
-
- GEN_OFFS(ConstMethod, _constants);
- GEN_OFFS(ConstMethod, _flags);
- GEN_OFFS(ConstMethod, _code_size);
- GEN_OFFS(ConstMethod, _name_index);
- GEN_OFFS(ConstMethod, _signature_index);
- printf("\n");
-
- GEN_OFFS(CodeHeap, _memory);
- GEN_OFFS(CodeHeap, _segmap);
- GEN_OFFS(CodeHeap, _log2_segment_size);
- printf("\n");
-
- GEN_OFFS(VirtualSpace, _low_boundary);
- GEN_OFFS(VirtualSpace, _high_boundary);
- GEN_OFFS(VirtualSpace, _low);
- GEN_OFFS(VirtualSpace, _high);
- printf("\n");
-
- /* We need to use different names here because of the template parameter */
- GEN_OFFS_NAME(GrowableArray, _data, GrowableArray_CodeHeap);
- GEN_OFFS_NAME(GrowableArray, _len, GrowableArray_CodeHeap);
- printf("\n");
-
- GEN_OFFS(CodeBlob, _name);
- GEN_OFFS(CodeBlob, _header_size);
- GEN_OFFS(CodeBlob, _content_begin);
- GEN_OFFS(CodeBlob, _code_begin);
- GEN_OFFS(CodeBlob, _code_end);
- GEN_OFFS(CodeBlob, _data_offset);
- GEN_OFFS(CodeBlob, _frame_size);
- printf("\n");
-
- GEN_OFFS(nmethod, _method);
- GEN_OFFS(nmethod, _dependencies_offset);
- GEN_OFFS(nmethod, _metadata_offset);
- GEN_OFFS(nmethod, _scopes_data_begin);
- GEN_OFFS(nmethod, _scopes_pcs_offset);
- GEN_OFFS(nmethod, _handler_table_offset);
- GEN_OFFS(nmethod, _deopt_handler_begin);
- GEN_OFFS(nmethod, _orig_pc_offset);
-
- GEN_OFFS(PcDesc, _pc_offset);
- GEN_OFFS(PcDesc, _scope_decode_offset);
-
- printf("\n");
-
- GEN_OFFS(NarrowPtrStruct, _base);
- GEN_OFFS(NarrowPtrStruct, _shift);
- printf("\n");
-
- GEN_VALUE(SIZE_HeapBlockHeader, (int) sizeof(HeapBlock::Header));
- GEN_SIZE(oopDesc);
- GEN_SIZE(ConstantPool);
- printf("\n");
-
- GEN_SIZE(PcDesc);
- GEN_SIZE(Method);
- GEN_SIZE(ConstMethod);
- GEN_SIZE(nmethod);
- GEN_SIZE(CodeBlob);
- GEN_SIZE(BufferBlob);
- GEN_SIZE(SingletonBlob);
- GEN_SIZE(RuntimeStub);
- GEN_SIZE(SafepointBlob);
-
- gen_epilogue(gen_variant);
- printf("\n");
-
- fflush(stdout);
- return 0;
-}
-
-const char *HELP =
- "HELP: generateJvmOffsets {-header | -index | -table} \n";
-
-int main(int argc, const char *argv[]) {
- GEN_variant gen_var;
-
- if (argc != 2) {
- printf("%s", HELP);
- return 1;
- }
-
- if (0 == strcmp(argv[1], "-header")) {
- gen_var = GEN_OFFSET;
- }
- else if (0 == strcmp(argv[1], "-index")) {
- gen_var = GEN_INDEX;
- }
- else if (0 == strcmp(argv[1], "-table")) {
- gen_var = GEN_TABLE;
- }
- else {
- printf("%s", HELP);
- return 1;
- }
- return generateJvmOffsets(gen_var);
-}
diff --git a/make/hotspot/symbols/symbols-solaris b/make/hotspot/symbols/symbols-solaris
deleted file mode 100644
index bc6124f83a3..00000000000
--- a/make/hotspot/symbols/symbols-solaris
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Copyright (c) 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.
-#
-
-JVM_handle_solaris_signal
-sysThreadAvailableStackWithSlack
diff --git a/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 b/make/hotspot/symbols/symbols-solaris-dtrace-compiler1
deleted file mode 100644
index 4ce7d8e30b2..00000000000
--- a/make/hotspot/symbols/symbols-solaris-dtrace-compiler1
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Copyright (c) 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.
-#
-
-__1cGMethodG__vtbl_
-__1cHnmethodG__vtbl_
-__1cICodeBlobG__vtbl_
-__1cIUniverseO_collectedHeap_
-__1cJCodeCacheG_heaps_
-__1cKBufferBlobG__vtbl_
-__1cLRuntimeStubG__vtbl_
-__1cNSafepointBlobG__vtbl_
-__1cSDeoptimizationBlobG__vtbl_
-
-__JvmOffsets
diff --git a/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 b/make/hotspot/symbols/symbols-solaris-dtrace-compiler2
deleted file mode 100644
index 306345e5c29..00000000000
--- a/make/hotspot/symbols/symbols-solaris-dtrace-compiler2
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Copyright (c) 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.
-#
-
-__1cGMethodG__vtbl_
-__1cHnmethodG__vtbl_
-__1cICodeBlobG__vtbl_
-__1cIUniverseO_collectedHeap_
-__1cJCodeCacheG_heaps_
-__1cKBufferBlobG__vtbl_
-__1cLRuntimeStubG__vtbl_
-__1cNSafepointBlobG__vtbl_
-__1cSDeoptimizationBlobG__vtbl_
-__1cNExceptionBlobG__vtbl_
-__1cQUncommonTrapBlobG__vtbl_
-
-__JvmOffsets
diff --git a/make/hotspot/test/GtestImage.gmk b/make/hotspot/test/GtestImage.gmk
index 744957dcf1a..74077e47987 100644
--- a/make/hotspot/test/GtestImage.gmk
+++ b/make/hotspot/test/GtestImage.gmk
@@ -56,14 +56,4 @@ ifeq ($(call isTargetOs, windows), true)
)
endif
-ifeq ($(call isTargetOs, solaris), true)
- $(foreach v, $(JVM_VARIANTS), \
- $(eval $(call SetupCopyFiles, COPY_GTEST_STLPORT_$v, \
- DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
- FILES := $(STLPORT_LIB), \
- )) \
- $(eval TARGETS += $$(COPY_GTEST_STLPORT_$v)) \
- )
-endif
-
all: $(TARGETS)
diff --git a/make/ide/netbeans/hotspot/nbproject/configurations.xml b/make/ide/netbeans/hotspot/nbproject/configurations.xml
index 7a98ad0f471..4f64db4ecf0 100644
--- a/make/ide/netbeans/hotspot/nbproject/configurations.xml
+++ b/make/ide/netbeans/hotspot/nbproject/configurations.xml
@@ -42,19 +42,6 @@
-
-
-
- ../..
- gmake -f Makefile images
- gmake -f Makefile clean
-
-
- ../..
- sh configure --with-debug-level=slowdebug
-
-
-
diff --git a/make/ide/netbeans/hotspot/nbproject/project.xml b/make/ide/netbeans/hotspot/nbproject/project.xml
index 68682851e5a..103d034d1cb 100644
--- a/make/ide/netbeans/hotspot/nbproject/project.xml
+++ b/make/ide/netbeans/hotspot/nbproject/project.xml
@@ -21,10 +21,6 @@
Linux_64
0
-
- Solaris_64
- 0
-
Windws64
0
diff --git a/make/ide/visualstudio/hotspot/CreateVSProject.gmk b/make/ide/visualstudio/hotspot/CreateVSProject.gmk
index 9872d17c0ac..b463beec435 100644
--- a/make/ide/visualstudio/hotspot/CreateVSProject.gmk
+++ b/make/ide/visualstudio/hotspot/CreateVSProject.gmk
@@ -84,8 +84,6 @@ ifeq ($(call isTargetOs, windows), true)
-ignorePath linux \
-ignorePath posix \
-ignorePath ppc \
- -ignorePath solaris \
- -ignorePath sparc \
-ignorePath x86_32 \
-ignorePath zero \
#
diff --git a/make/langtools/build.xml b/make/langtools/build.xml
index efd0a9e9d65..93349c44934 100644
--- a/make/langtools/build.xml
+++ b/make/langtools/build.xml
@@ -1,6 +1,6 @@
diff --git a/make/modules/java.base/Copy.gmk b/make/modules/java.base/Copy.gmk
index c2251fa18af..9071f4e6e37 100644
--- a/make/modules/java.base/Copy.gmk
+++ b/make/modules/java.base/Copy.gmk
@@ -149,7 +149,7 @@ DEF_POLICY_DST := $(LIB_DST_DIR)/security/default.policy
DEF_POLICY_SRC_LIST := $(DEF_POLICY_SRC)
DEF_POLICY_SRC_LIST += $(CUSTOM_POLICY_SRC_LIST)
-ifeq ($(call isTargetOs, windows solaris), true)
+ifeq ($(call isTargetOs, windows), true)
DEF_POLICY_SRC_LIST += $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/lib/security/default.policy
endif
@@ -189,7 +189,7 @@ $(eval $(call SetupCopyFiles, COPY_NET_PROPERTIES, \
TARGETS += $(COPY_NET_PROPERTIES)
-ifeq ($(call isTargetOs, solaris linux), true)
+ifeq ($(call isTargetOs, linux), true)
$(eval $(call SetupCopyFiles, COPY_SDP_CONF, \
FILES := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/sdp/sdp.conf.template, \
DEST := $(CONF_DST_DIR)/sdp, \
diff --git a/make/modules/java.base/Launcher.gmk b/make/modules/java.base/Launcher.gmk
index 92b668788b4..3a04ee387ea 100644
--- a/make/modules/java.base/Launcher.gmk
+++ b/make/modules/java.base/Launcher.gmk
@@ -65,7 +65,6 @@ ifeq ($(call isTargetOs, linux), true)
CFLAGS := $(CFLAGS_JDKEXE) \
-I$(TOPDIR)/src/$(MODULE)/share/native/libjli, \
CFLAGS_linux := -fPIC, \
- CFLAGS_solaris := -KPIC, \
LDFLAGS := $(LDFLAGS_JDKEXE), \
OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE), \
))
@@ -75,7 +74,7 @@ endif
################################################################################
-ifeq ($(call isTargetOs, macosx solaris aix linux), true)
+ifeq ($(call isTargetOs, macosx aix linux), true)
$(eval $(call SetupJdkExecutable, BUILD_JSPAWNHELPER, \
NAME := jspawnhelper, \
SRC := $(TOPDIR)/src/$(MODULE)/unix/native/jspawnhelper, \
diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk
index 9f33e2340b8..40ad7b3de4f 100644
--- a/make/modules/java.base/Lib.gmk
+++ b/make/modules/java.base/Lib.gmk
@@ -47,13 +47,11 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBNET, \
DISABLED_WARNINGS_clang := parentheses-equality constant-logical-operand \
format-nonliteral undef, \
DISABLED_WARNINGS_microsoft := 4244 4047 4133 4996, \
- DISABLED_WARNINGS_solstudio := E_ARG_INCOMPATIBLE_WITH_ARG_L, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_windows := -delayload:secur32.dll -delayload:iphlpapi.dll, \
LIBS_unix := -ljvm -ljava, \
LIBS_linux := $(LIBDL) -lpthread, \
- LIBS_solaris := -lnsl -lsocket $(LIBDL), \
LIBS_aix := $(LIBDL),\
LIBS_windows := ws2_32.lib jvm.lib secur32.lib iphlpapi.lib winhttp.lib \
delayimp.lib $(WIN_JAVA_LIB) advapi32.lib, \
@@ -82,8 +80,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBNIO, \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS_unix := -ljava -lnet, \
LIBS_linux := -lpthread $(LIBDL), \
- LIBS_solaris := -ljvm -lsocket -lposix4 $(LIBDL) \
- -lsendfile, \
LIBS_aix := $(LIBDL), \
LIBS_macosx := \
-framework CoreFoundation -framework CoreServices, \
@@ -140,7 +136,6 @@ ifeq ($(call isTargetOsType, unix), true)
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS_linux := $(LIBDL), \
- LIBS_solaris := $(LIBDL), \
LIBS_aix := $(LIBDL), \
))
diff --git a/make/modules/java.base/gensrc/GensrcMisc.gmk b/make/modules/java.base/gensrc/GensrcMisc.gmk
index 0863f4fa4ec..cd12f2ab318 100644
--- a/make/modules/java.base/gensrc/GensrcMisc.gmk
+++ b/make/modules/java.base/gensrc/GensrcMisc.gmk
@@ -104,21 +104,6 @@ ifeq ($(call isTargetOs, windows), false)
endif
-################################################################################
-
-ifeq ($(call isTargetOs, solaris), true)
-
- GENSRC_SC_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/SolarisConstants.java
-
- $(GENSRC_SC_FILE): \
- $(TOPDIR)/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template
- $(generate-preproc-src)
-
- TARGETS += $(GENSRC_SC_FILE)
-
-endif
-
-################################################################################
# Create the javax/crypto/JceSecurity.class, using the build default.
#
ifeq ($(UNLIMITED_CRYPTO), true)
diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk
index ab8a75cf454..e5c54212347 100644
--- a/make/modules/java.base/lib/CoreLibraries.gmk
+++ b/make/modules/java.base/lib/CoreLibraries.gmk
@@ -29,10 +29,6 @@
BUILD_LIBFDLIBM_OPTIMIZATION := NONE
-ifeq ($(call isTargetOs, solaris), true)
- BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
-endif
-
# If FDLIBM_CFLAGS is non-empty we know that we can optimize
# fdlibm when adding those extra C flags. Currently GCC,
# and clang only.
@@ -62,7 +58,7 @@ $(eval $(call SetupNativeCompilation, BUILD_LIBFDLIBM, \
##########################################################################################
LIBVERIFY_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, solaris linux), true)
+ifeq ($(call isTargetOs, linux), true)
ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true)
LIBVERIFY_OPTIMIZATION := LOW
endif
@@ -98,7 +94,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \
EXTRA_HEADER_DIRS := libfdlibm, \
WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc := unused-result unused-function, \
- DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_macosx := -L$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/, \
@@ -106,7 +101,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \
LIBS := $(BUILD_LIBFDLIBM_TARGET), \
LIBS_unix := -ljvm, \
LIBS_linux := $(LIBDL), \
- LIBS_solaris := -lsocket -lnsl -lscf $(LIBDL), \
LIBS_aix := $(LIBDL) $(LIBM),\
LIBS_macosx := -framework CoreFoundation \
-framework Foundation \
@@ -215,7 +209,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJLI, \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS_unix := $(LIBZ_LIBS), \
LIBS_linux := $(LIBDL) -lpthread, \
- LIBS_solaris := $(LIBDL), \
LIBS_aix := $(LIBDL),\
LIBS_macosx := -framework Cocoa -framework Security -framework ApplicationServices, \
LIBS_windows := advapi32.lib comctl32.lib user32.lib, \
diff --git a/make/modules/java.desktop/Gensrc.gmk b/make/modules/java.desktop/Gensrc.gmk
index efa823a044e..1fc36f005c2 100644
--- a/make/modules/java.desktop/Gensrc.gmk
+++ b/make/modules/java.desktop/Gensrc.gmk
@@ -32,7 +32,7 @@ ifeq ($(call isTargetOs, windows), false)
include gensrc/GensrcIcons.gmk
endif
-ifeq ($(call isTargetOs, linux solaris aix), true)
+ifeq ($(call isTargetOs, linux aix), true)
include gensrc/GensrcX11Wrappers.gmk
endif
diff --git a/make/modules/java.desktop/Lib.gmk b/make/modules/java.desktop/Lib.gmk
index c72cbdb9929..954f0933b0b 100644
--- a/make/modules/java.desktop/Lib.gmk
+++ b/make/modules/java.desktop/Lib.gmk
@@ -46,15 +46,10 @@ ifeq ($(call isTargetOs, aix), false)
-DX_PLATFORM=X_$(OPENJDK_TARGET_OS_UPPERCASE) \
-DUSE_PORTS=TRUE \
-DUSE_DAUDIO=TRUE \
+ -DUSE_PLATFORM_MIDI_OUT=TRUE \
+ -DUSE_PLATFORM_MIDI_IN=TRUE \
#
- ifeq ($(call isTargetOs, solaris), false)
- LIBJSOUND_CFLAGS += \
- -DUSE_PLATFORM_MIDI_OUT=TRUE \
- -DUSE_PLATFORM_MIDI_IN=TRUE \
- #
- endif
-
ifeq ($(call isTargetOs, macosx), true)
LIBJSOUND_TOOLCHAIN := TOOLCHAIN_LINK_CXX
endif
diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
index 0c0dee57275..4d7cddc49f8 100644
--- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk
+++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
@@ -67,10 +67,6 @@ LIBAWT_EXTRA_SRC := \
$(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \
#
-ifeq ($(call And, $(call isTargetOs, solaris) $(call isTargetCpuArch, sparc)), true)
- LIBAWT_EXTRA_SRC += $(TOPDIR)/src/$(MODULE)/share/native/common/awt/medialib
-endif
-
ifeq ($(call isTargetOs, windows), true)
LIBAWT_EXTRA_SRC += \
$(TOPDIR)/src/$(MODULE)/share/native/common/awt/utility \
@@ -80,7 +76,7 @@ ifeq ($(call isTargetOs, windows), true)
#
endif
-ifeq ($(call isTargetOs, solaris linux macosx aix), true)
+ifeq ($(call isTargetOs, linux macosx aix), true)
LIBAWT_EXFILES += awt_Font.c CUPSfuncs.c fontpath.c X11Color.c
endif
@@ -112,13 +108,7 @@ LIBAWT_EXTRA_HEADER_DIRS := \
LIBAWT_CFLAGS += -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES $(X_CFLAGS)
-ifeq ($(call And, $(call isTargetOs, solaris) $(call isTargetCpu, sparcv9)), true)
- LIBAWT_ASFLAGS = -P -xarch=v9a
-endif
-
-ifeq ($(call isTargetOs, solaris), false)
- LIBAWT_CFLAGS += -DMLIB_NO_LIBSUNMATH
-endif
+LIBAWT_CFLAGS += -DMLIB_NO_LIBSUNMATH
ifeq ($(call isTargetOs, windows), true)
LIBAWT_CFLAGS += -EHsc -DUNICODE -D_UNICODE
@@ -157,7 +147,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
DISABLED_WARNINGS_clang := logical-op-parentheses extern-initializer \
sign-compare format-nonliteral, \
DISABLED_WARNINGS_microsoft := 4244 4267 4996, \
- ASFLAGS := $(LIBAWT_ASFLAGS), \
LDFLAGS := $(LDFLAGS_JDKLIB) $(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_macosx := -L$(INSTALL_LIBRARIES_HERE), \
LDFLAGS_windows := -delayload:user32.dll -delayload:gdi32.dll \
@@ -167,7 +156,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
-delayload:comctl32.dll -delayload:shlwapi.dll, \
LIBS_unix := -ljvm -ljava $(LIBM), \
LIBS_linux := $(LIBDL), \
- LIBS_solaris := $(LIBDL), \
LIBS_aix := $(LIBDL),\
LIBS_macosx := -lmlib_image \
-framework Cocoa \
@@ -223,10 +211,6 @@ ifeq ($(call isTargetOs, windows macosx), false)
$(FONTCONFIG_CFLAGS) \
$(CUPS_CFLAGS)
- ifeq ($(call isTargetOs, solaris), true)
- LIBAWT_XAWT_CFLAGS += -DFUNCPROTO=15
- endif
-
ifeq ($(call isTargetOs, linux), true)
ifeq ($(DISABLE_XRENDER), true)
LIBAWT_XAWT_CFLAGS += -DDISABLE_XRENDER_BY_DEFAULT=true
@@ -265,8 +249,6 @@ ifeq ($(call isTargetOs, windows macosx), false)
implicit-fallthrough undef unused-function, \
DISABLED_WARNINGS_clang := parentheses format undef \
logical-op-parentheses format-nonliteral int-conversion, \
- DISABLED_WARNINGS_solstudio := E_ASSIGNMENT_TYPE_MISMATCH \
- E_NON_CONST_INIT, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN) \
-L$(INSTALL_LIBRARIES_HERE), \
@@ -312,7 +294,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBLCMS, \
DISABLED_WARNINGS_gcc := format-nonliteral type-limits \
misleading-indentation undef unused-function stringop-truncation, \
DISABLED_WARNINGS_clang := tautological-compare format-nonliteral undef, \
- DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
DISABLED_WARNINGS_microsoft := 4819, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
@@ -397,13 +378,11 @@ ifeq ($(call isTargetOs, windows macosx), false)
$(LIBAWT_HEADLESS_CFLAGS), \
EXTRA_HEADER_DIRS := $(LIBAWT_HEADLESS_EXTRA_HEADER_DIRS), \
DISABLED_WARNINGS_gcc := unused-function, \
- DISABLED_WARNINGS_solstudio := E_EMPTY_TRANSLATION_UNIT, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
LIBS_unix := -lawt -ljvm -ljava, \
LIBS_linux := $(LIBM) $(LIBDL), \
- LIBS_solaris := $(LIBM) $(LIBDL) $(LIBCXX), \
))
$(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT)
@@ -438,9 +417,6 @@ else
CFLAGS := $(CFLAGS_JDKLIB) \
$(BUILD_LIBFREETYPE_CFLAGS), \
EXTRA_HEADER_DIRS := $(BUILD_LIBFREETYPE_HEADER_DIRS), \
- DISABLED_WARNINGS_solstudio := \
- E_STATEMENT_NOT_REACHED \
- E_END_OF_LOOP_CODE_NOT_REACHED, \
DISABLED_WARNINGS_microsoft := 4018 4267 4244 4312 4819, \
DISABLED_WARNINGS_gcc := implicit-fallthrough cast-function-type bad-function-cast, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
@@ -464,9 +440,6 @@ endif
ifeq ($(call isTargetOs, linux macosx), true)
HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES
endif
-ifeq ($(call isTargetOs, solaris), true)
- HARFBUZZ_CFLAGS += -DHAVE_SOLARIS_ATOMIC_OPS
-endif
ifeq ($(call isTargetOs, macosx), true)
HARFBUZZ_CFLAGS += -DHAVE_CORETEXT
endif
@@ -540,14 +513,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \
DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \
tautological-constant-out-of-range-compare int-to-pointer-cast \
sign-compare undef missing-field-initializers, \
- DISABLED_WARNINGS_C_solstudio = \
- E_INTEGER_OVERFLOW_DETECTED \
- E_ARG_INCOMPATIBLE_WITH_ARG_L \
- E_ENUM_VAL_OVERFLOWS_INT_MAX, \
- DISABLED_WARNINGS_CXX_solstudio := \
- truncwarn wvarhidenmem wvarhidemem wbadlkginit identexpected \
- hidevf w_novirtualdescr arrowrtn2 refmemnoconstr_aggr unknownpragma \
- doubunder wunreachable, \
DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334 4819 4101 4068 4805 4138, \
LDFLAGS := $(subst -Xlinker -z -Xlinker defs,, \
$(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB))) $(LDFLAGS_CXX_JDK) \
@@ -626,10 +591,7 @@ else # not windows
ifeq ($(call isTargetOs, macosx), true)
JAWT_LIBS := -lawt_lwawt
else
- JAWT_LIBS :=
- ifeq ($(call isTargetOs, solaris), false)
- JAWT_LIBS += -lawt
- endif
+ JAWT_LIBS := -lawt
ifeq ($(ENABLE_HEADLESS_ONLY), false)
JAWT_LIBS += -lawt_xawt
else
@@ -656,7 +618,6 @@ else # not windows
LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \
LIBS_unix := $(JAWT_LIBS) $(JDKLIB_LIBS), \
- LIBS_solaris := $(X_LIBS) -lXrender, \
LIBS_macosx := -framework Cocoa, \
))
@@ -775,7 +736,6 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
maybe-uninitialized shift-negative-value implicit-fallthrough \
unused-function, \
DISABLED_WARNINGS_clang := incompatible-pointer-types sign-compare, \
- DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
DISABLED_WARNINGS_microsoft := 4018 4244 4267, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
diff --git a/make/modules/java.instrument/Lib.gmk b/make/modules/java.instrument/Lib.gmk
index 6a28ba9dbfb..3996ad21386 100644
--- a/make/modules/java.instrument/Lib.gmk
+++ b/make/modules/java.instrument/Lib.gmk
@@ -45,13 +45,11 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBINSTRUMENT, \
$(call SET_SHARED_LIBRARY_ORIGIN) \
$(LIBINSTRUMENT_LDFLAGS), \
LDFLAGS_linux := -L$(call FindLibDirForModule, java.base), \
- LDFLAGS_solaris := -L$(call FindLibDirForModule, java.base), \
LDFLAGS_macosx := -L$(call FindLibDirForModule, java.base), \
LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
LIBS := $(JDKLIB_LIBS), \
LIBS_unix := -ljava -ljvm $(LIBZ_LIBS), \
LIBS_linux := -ljli $(LIBDL), \
- LIBS_solaris := -ljli $(LIBDL), \
LIBS_aix := -liconv -ljli_static $(LIBDL), \
LIBS_macosx := -ljli -liconv -framework Cocoa -framework Security \
-framework ApplicationServices, \
diff --git a/make/modules/java.management/Lib.gmk b/make/modules/java.management/Lib.gmk
index 1817d266476..ea2ff706d7a 100644
--- a/make/modules/java.management/Lib.gmk
+++ b/make/modules/java.management/Lib.gmk
@@ -28,7 +28,7 @@ include LibCommon.gmk
################################################################################
LIBMANAGEMENT_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, solaris linux), true)
+ifeq ($(call isTargetOs, linux), true)
ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true)
LIBMANAGEMENT_OPTIMIZATION := LOW
endif
@@ -41,7 +41,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBMANAGEMENT, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(JDKLIB_LIBS), \
- LIBS_solaris := -lkstat, \
LIBS_aix := -lperfstat,\
LIBS_windows := jvm.lib psapi.lib $(WIN_JAVA_LIB) advapi32.lib, \
))
diff --git a/make/modules/java.prefs/Lib.gmk b/make/modules/java.prefs/Lib.gmk
index a7b0ef75020..74144cff24e 100644
--- a/make/modules/java.prefs/Lib.gmk
+++ b/make/modules/java.prefs/Lib.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBPREFS, \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS_unix := -ljvm, \
LIBS_linux := -ljava, \
- LIBS_solaris := -ljava, \
LIBS_aix := -ljava, \
LIBS_macosx := -framework CoreFoundation -framework Foundation, \
LIBS_windows := advapi32.lib jvm.lib $(WIN_JAVA_LIB), \
diff --git a/make/modules/jdk.aot/Launcher.gmk b/make/modules/jdk.aot/Launcher.gmk
index 10717a5e1c5..5025ceaf7f1 100644
--- a/make/modules/jdk.aot/Launcher.gmk
+++ b/make/modules/jdk.aot/Launcher.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -42,10 +42,8 @@ $(eval $(call SetupBuildLauncher, jaotc, \
JAVA_ARGS := --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
- --add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.sparc=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.meta=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.runtime=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
- --add-exports=jdk.internal.vm.ci/jdk.vm.ci.sparc=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
-XX:+UnlockExperimentalVMOptions -XX:+UseAOT \
-XX:+CalculateClassFingerprint \
-Djvmci.UseProfilingInformation=false \
diff --git a/make/modules/jdk.attach/Lib.gmk b/make/modules/jdk.attach/Lib.gmk
index 692eaa39e2c..6c61926b804 100644
--- a/make/modules/jdk.attach/Lib.gmk
+++ b/make/modules/jdk.attach/Lib.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBATTACH, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(JDKLIB_LIBS), \
- LIBS_solaris := -ldoor, \
LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib psapi.lib, \
))
diff --git a/make/modules/jdk.crypto.cryptoki/Copy.gmk b/make/modules/jdk.crypto.cryptoki/Copy.gmk
deleted file mode 100644
index d6ddde57bd9..00000000000
--- a/make/modules/jdk.crypto.cryptoki/Copy.gmk
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include CopyCommon.gmk
-
-################################################################################
-
-ifeq ($(call isTargetOs, solaris), true)
-
- SUNPKCS11_CFG_SRC := \
- $(TOPDIR)/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg
- SUNPKCS11_CFG_DST := $(CONF_DST_DIR)/security/sunpkcs11-solaris.cfg
-
- $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
- $(call install-file)
-
- SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST)
-
- TARGETS := $(SUNPKCS11_CFG_DST)
-
-endif
-
-################################################################################
diff --git a/make/modules/jdk.crypto.ucrypto/Copy.gmk b/make/modules/jdk.crypto.ucrypto/Copy.gmk
deleted file mode 100644
index afec200e8f5..00000000000
--- a/make/modules/jdk.crypto.ucrypto/Copy.gmk
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include CopyCommon.gmk
-
-################################################################################
-
-ifeq ($(call isTargetOs, solaris), true)
-
- UCRYPTO_CFG_SRC := $(TOPDIR)/src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg
- UCRYPTO_CFG_DST := $(CONF_DST_DIR)/security/ucrypto-solaris.cfg
-
- $(UCRYPTO_CFG_DST): $(UCRYPTO_CFG_SRC)
- $(call install-file)
-
- TARGETS += $(UCRYPTO_CFG_DST)
-
-endif
-
-################################################################################
diff --git a/make/modules/jdk.crypto.ucrypto/Lib.gmk b/make/modules/jdk.crypto.ucrypto/Lib.gmk
deleted file mode 100644
index e7fd701ef55..00000000000
--- a/make/modules/jdk.crypto.ucrypto/Lib.gmk
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation. Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-include LibCommon.gmk
-
-################################################################################
-
-ifeq ($(call isTargetOs, solaris), true)
-
- $(eval $(call SetupJdkLibrary, BUILD_LIBJ2UCRYPTO, \
- NAME := j2ucrypto, \
- OPTIMIZATION := LOW, \
- CFLAGS := $(CFLAGS_JDKLIB), \
- LDFLAGS := $(LDFLAGS_JDKLIB), \
- LIBS := $(LIBDL), \
- ))
-
- $(BUILD_LIBJ2UCRYPTO): $(call FindLib, java.base, java)
-
- TARGETS += $(BUILD_LIBJ2UCRYPTO)
-
-endif
-
-################################################################################
diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk
index c7bb98f313e..40f843c03f4 100644
--- a/make/modules/jdk.hotspot.agent/Lib.gmk
+++ b/make/modules/jdk.hotspot.agent/Lib.gmk
@@ -30,9 +30,6 @@ include LibCommon.gmk
ifeq ($(call isTargetOs, linux), true)
SA_CFLAGS := -D_FILE_OFFSET_BITS=64
-else ifeq ($(call isTargetOs, solaris), true)
- SA_LDFLAGS := -mt
-
else ifeq ($(call isTargetOs, macosx), true)
SA_CFLAGS := -Damd64 -D_GNU_SOURCE -mno-omit-leaf-frame-pointer \
-mstack-alignment=16 -fPIC
@@ -65,13 +62,11 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSA, \
DISABLED_WARNINGS_microsoft := 4267, \
DISABLED_WARNINGS_gcc := sign-compare pointer-arith, \
DISABLED_WARNINGS_clang := sign-compare pointer-arith format-nonliteral, \
- DISABLED_WARNINGS_CXX_solstudio := truncwarn unknownpragma doubunder, \
CFLAGS := $(CFLAGS_JDKLIB) $(SA_CFLAGS), \
CXXFLAGS := $(CXXFLAGS_JDKLIB) $(SA_CFLAGS) $(SA_CXXFLAGS), \
EXTRA_SRC := $(LIBSA_EXTRA_SRC), \
- LDFLAGS := $(LDFLAGS_JDKLIB) $(SA_LDFLAGS), \
+ LDFLAGS := $(LDFLAGS_JDKLIB), \
LIBS_linux := $(LIBDL), \
- LIBS_solaris := -ldl -ldemangle -lthread -lproc, \
LIBS_macosx := -framework Foundation -framework JavaNativeFoundation \
-framework JavaRuntimeSupport -framework Security -framework CoreFoundation, \
LIBS_windows := dbgeng.lib, \
diff --git a/make/modules/jdk.internal.vm.compiler/Gensrc.gmk b/make/modules/jdk.internal.vm.compiler/Gensrc.gmk
index 7efd9ccb484..d4479e96cc8 100644
--- a/make/modules/jdk.internal.vm.compiler/Gensrc.gmk
+++ b/make/modules/jdk.internal.vm.compiler/Gensrc.gmk
@@ -35,12 +35,10 @@ PROC_SRC_SUBDIRS := \
org.graalvm.compiler.core.aarch64 \
org.graalvm.compiler.core.amd64 \
org.graalvm.compiler.core.common \
- org.graalvm.compiler.core.sparc \
org.graalvm.compiler.debug \
org.graalvm.compiler.hotspot \
org.graalvm.compiler.hotspot.aarch64 \
org.graalvm.compiler.hotspot.amd64 \
- org.graalvm.compiler.hotspot.sparc \
org.graalvm.compiler.graph \
org.graalvm.compiler.java \
org.graalvm.compiler.lir \
@@ -85,13 +83,11 @@ ADD_EXPORTS := \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.events=jdk.internal.vm.compiler \
- --add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspot.sparc=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.hotspotvmconfig=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.inittimer=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.meta=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.runtime=jdk.internal.vm.compiler \
--add-exports jdk.internal.vm.ci/jdk.vm.ci.services=jdk.internal.vm.compiler \
- --add-exports jdk.internal.vm.ci/jdk.vm.ci.sparc=jdk.internal.vm.compiler \
#
$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) $(PROCESSOR_JARS)
diff --git a/make/modules/jdk.jdwp.agent/Lib.gmk b/make/modules/jdk.jdwp.agent/Lib.gmk
index dd8cbe25cc3..b49284c020e 100644
--- a/make/modules/jdk.jdwp.agent/Lib.gmk
+++ b/make/modules/jdk.jdwp.agent/Lib.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBDT_SOCKET, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS_linux := -lpthread, \
- LIBS_solaris := -lnsl -lsocket, \
LIBS_windows := $(JDKLIB_LIBS) ws2_32.lib iphlpapi.lib, \
))
@@ -63,7 +62,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJDWP, \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(JDKLIB_LIBS), \
LIBS_linux := $(LIBDL), \
- LIBS_solaris := $(LIBDL), \
LIBS_macosx := -liconv, \
LIBS_aix := -liconv, \
LIBS_windows := $(WIN_JAVA_LIB), \
diff --git a/make/modules/jdk.management/Lib.gmk b/make/modules/jdk.management/Lib.gmk
index 6118d2effac..568b450facd 100644
--- a/make/modules/jdk.management/Lib.gmk
+++ b/make/modules/jdk.management/Lib.gmk
@@ -35,7 +35,7 @@ ifeq ($(call isTargetOs, windows), true)
endif
LIBMANAGEMENT_EXT_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, solaris linux), true)
+ifeq ($(call isTargetOs, linux), true)
ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true)
LIBMANAGEMENT_EXT_OPTIMIZATION := LOW
endif
@@ -49,7 +49,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBMANAGEMENT_EXT, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(JDKLIB_LIBS), \
- LIBS_solaris := -lkstat, \
LIBS_aix := -lperfstat,\
LIBS_windows := jvm.lib psapi.lib $(WIN_JAVA_LIB) advapi32.lib, \
))
diff --git a/make/modules/jdk.net/Lib.gmk b/make/modules/jdk.net/Lib.gmk
index 8e11c451510..3c9d1055fcc 100644
--- a/make/modules/jdk.net/Lib.gmk
+++ b/make/modules/jdk.net/Lib.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@ include LibCommon.gmk
################################################################################
-ifeq ($(call isTargetOs, solaris linux macosx), true)
+ifeq ($(call isTargetOs, linux macosx), true)
$(eval $(call SetupJdkLibrary, BUILD_LIBEXTNET, \
NAME := extnet, \
@@ -36,7 +36,6 @@ ifeq ($(call isTargetOs, solaris linux macosx), true)
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := -ljava, \
- LIBS_solaris := -lsocket, \
LIBS_linux := -ljvm, \
))
diff --git a/make/modules/jdk.sctp/Lib.gmk b/make/modules/jdk.sctp/Lib.gmk
index 2ba10034348..9aef8b53d0b 100644
--- a/make/modules/jdk.sctp/Lib.gmk
+++ b/make/modules/jdk.sctp/Lib.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -44,7 +44,6 @@ ifeq ($(call isTargetOsType, unix), true)
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS_unix := -lnio -lnet -ljava -ljvm, \
LIBS_linux := -lpthread $(LIBDL), \
- LIBS_solaris := -lsocket, \
))
TARGETS += $(BUILD_LIBSCTP)
diff --git a/make/scripts/compare.sh b/make/scripts/compare.sh
index 813e9bead20..25630199a21 100644
--- a/make/scripts/compare.sh
+++ b/make/scripts/compare.sh
@@ -72,26 +72,7 @@ fi
# Disassembly diff filters. These filters try to filter out ephemeral parts of the
# disassembly, such as hard-coded addresses, to be able to catch "actual" differences.
-if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
- if [ "$OPENJDK_TARGET_CPU" = "sparcv9" ]; then
- DIS_DIFF_FILTER="$SED \
- -e 's/^[0-9a-f]\{16\}/:/' \
- -e 's/^ *[0-9a-f]\{3,12\}:/ :/' \
- -e 's/: [0-9a-f][0-9a-f]\( [0-9a-f][0-9a-f]\)\{2,10\}/: /' \
- -e 's/\$[a-zA-Z0-9_\$]\{15\}\././' \
- -e 's/, [0-9a-fx\-]\{1,8\}/, /g' \
- -e 's/0x[0-9a-f]\{1,8\}//g' \
- -e 's/\! [0-9a-f]\{1,8\} /! /' \
- -e 's/call [0-9a-f]\{4,7\}/call /' \
- -e 's/%hi(0),/%hi(),/' \
- "
- elif [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then
- # Random strings looking like this differ: <.XAKoKoPIac2W0OA.
- DIS_DIFF_FILTER="$SED \
- -e 's/<\.[A-Za-z0-9]\{\15}\./<.SYM./' \
- "
- fi
-elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then
+if [ "$OPENJDK_TARGET_OS" = "windows" ]; then
if [ "$OPENJDK_TARGET_CPU" = "x86" ]; then
DIS_DIFF_FILTER="$SED -r \
-e 's/^ [0-9A-F]{16}: //' \
@@ -458,14 +439,7 @@ compare_zip_file() {
fi
CONTENTS_DIFF_FILE=$WORK_DIR/$ZIP_FILE.diff
- # On solaris, there is no -q option.
- if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
- $DIFF -r $OTHER_UNZIPDIR $THIS_UNZIPDIR \
- | $GREP -v -e "^<" -e "^>" -e "^Common subdirectories:" \
- > $CONTENTS_DIFF_FILE
- else
- $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE
- fi
+ $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE
ONLY_OTHER=$($GREP "^Only in $OTHER_UNZIPDIR" $CONTENTS_DIFF_FILE)
ONLY_THIS=$($GREP "^Only in $THIS_UNZIPDIR" $CONTENTS_DIFF_FILE)
@@ -485,14 +459,8 @@ compare_zip_file() {
fi
if [ "$CMP_ZIPS_CONTENTS" = "true" ]; then
- if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
- DIFFING_FILES=$($GREP -e 'differ$' -e '^diff ' $CONTENTS_DIFF_FILE \
- | $SED -e 's/^Files //g' -e 's/diff -r //g' | $CUT -f 1 -d ' ' \
- | $SED "s|$OTHER_UNZIPDIR/||g")
- else
- DIFFING_FILES=$($GREP -e "differ$" $CONTENTS_DIFF_FILE \
- | $CUT -f 2 -d ' ' | $SED "s|$OTHER_UNZIPDIR/||g")
- fi
+ DIFFING_FILES=$($GREP -e "differ$" $CONTENTS_DIFF_FILE \
+ | $CUT -f 2 -d ' ' | $SED "s|$OTHER_UNZIPDIR/||g")
# Separate executable/library files from other files in zip.
DIFFING_TEXT_FILES=
@@ -829,10 +797,6 @@ compare_bin_file() {
# to filter out that extra information.
$DUMPBIN -exports $OTHER_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
$DUMPBIN -exports $THIS_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
- elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
- # Some symbols get seemingly random 15 character prefixes. Filter them out.
- $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
- $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
elif [ "$OPENJDK_TARGET_OS" = "aix" ]; then
$OBJDUMP -T $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
$OBJDUMP -T $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
diff --git a/make/scripts/compare_exceptions.sh.incl b/make/scripts/compare_exceptions.sh.incl
index 897331e9e0a..1c71a7605ce 100644
--- a/make/scripts/compare_exceptions.sh.incl
+++ b/make/scripts/compare_exceptions.sh.incl
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -45,21 +45,6 @@ if [ "$OPENJDK_TARGET_OS" = "linux" ]; then
./hotspot/gtest/server/libjvm.so
"
fi
-elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
- SKIP_BIN_DIFF="true"
- SKIP_FULLDUMP_DIFF="true"
- MAX_KNOWN_DIS_DIFF_SIZE="3000"
- SORT_SYMBOLS="
- ./lib/libfontmanager.so
- ./lib/libjimage.so
- ./lib/server/libjvm.so
- ./hotspot/gtest/server/libjvm.so
- "
- KNOWN_DIS_DIFF="
- ./lib/libfontmanager.so
- ./lib/libsaproc.so
- "
- STRIP_TESTS_BEFORE_COMPARE="true"
elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then
SKIP_BIN_DIFF="true"
SKIP_FULLDUMP_DIFF="true"
diff --git a/make/scripts/hide_important_warnings_from_javac.sh b/make/scripts/hide_important_warnings_from_javac.sh
index 04336350a74..392ed33247a 100644
--- a/make/scripts/hide_important_warnings_from_javac.sh
+++ b/make/scripts/hide_important_warnings_from_javac.sh
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -22,13 +22,8 @@
# questions.
#
-if [ -x /usr/bin/ggrep ] ; then
- # Gnu grep on Solaris
- # (reference configure and build/solaris-i586-clientANDserver-release/spec.gmk
- GREP=/usr/bin/ggrep
-else
- GREP=grep
-fi
+GREP=grep
+
#
EXP="Note: Some input files use or override a deprecated API."
EXP="${EXP}|Note: Recompile with -Xlint:deprecation for details."
diff --git a/make/scripts/update_copyright_year.sh b/make/scripts/update_copyright_year.sh
index cd7f4895d85..0f9ba80fc5a 100644
--- a/make/scripts/update_copyright_year.sh
+++ b/make/scripts/update_copyright_year.sh
@@ -1,7 +1,7 @@
#!/bin/bash -f
#
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -26,11 +26,7 @@
# Script to update the Copyright YEAR range in Mercurial sources.
# (Originally from xdono, Thanks!)
-if [ "`uname -s`" = "SunOS" ] ; then
- awk=nawk
-else
- awk=awk
-fi
+awk=awk
# Stop on any error
set -e
diff --git a/make/test/JtregGraalUnit.gmk b/make/test/JtregGraalUnit.gmk
index f2403b78bb8..fcfbc3b864a 100644
--- a/make/test/JtregGraalUnit.gmk
+++ b/make/test/JtregGraalUnit.gmk
@@ -85,7 +85,6 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.api.test/src \
$(SRC_DIR)/org.graalvm.compiler.asm.aarch64.test/src \
$(SRC_DIR)/org.graalvm.compiler.asm.amd64.test/src \
- $(SRC_DIR)/org.graalvm.compiler.asm.sparc.test/src \
$(SRC_DIR)/org.graalvm.compiler.asm.test/src \
$(SRC_DIR)/org.graalvm.compiler.core.aarch64.test/src \
$(SRC_DIR)/org.graalvm.compiler.core.amd64.test/src \
@@ -98,7 +97,6 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.hotspot.jdk15.test/src \
$(SRC_DIR)/org.graalvm.compiler.hotspot.jdk9.test/src \
$(SRC_DIR)/org.graalvm.compiler.hotspot.lir.test/src \
- $(SRC_DIR)/org.graalvm.compiler.hotspot.sparc.test/src \
$(SRC_DIR)/org.graalvm.compiler.hotspot.test/src \
$(SRC_DIR)/org.graalvm.compiler.jtt/src \
$(SRC_DIR)/org.graalvm.compiler.lir.jtt/src \
diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk
index 58837e00158..5c58a042a2e 100644
--- a/make/test/JtregNativeHotspot.gmk
+++ b/make/test/JtregNativeHotspot.gmk
@@ -850,10 +850,6 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libVirtualMachine09agent00 := $(NSK_AOD_INC
################################################################################
# Platform specific setup
-ifeq ($(call And, $(call isTargetOs, solaris) $(call isTargetCpuArch, sparc)), false)
- BUILD_HOTSPOT_JTREG_EXCLUDE += liboverflow.c exeThreadSignalMask.c
-endif
-
ifeq ($(call isTargetOs, linux), true)
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libtest-rw := -z noexecstack
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libtest-rwx := -z execstack
@@ -873,10 +869,6 @@ endif
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exesigtest := -ljvm
-ifeq ($(call isTargetOs, solaris), true)
- BUILD_HOTSPOT_JTREG_EXCLUDE += libterminatedThread.c
-endif
-
ifeq ($(call isTargetOs, windows), true)
BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT
BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c
diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk
index e0541a89110..ecd587c3d3d 100644
--- a/make/test/JtregNativeJdk.gmk
+++ b/make/test/JtregNativeJdk.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -70,9 +70,6 @@ else
ifeq ($(call isTargetOs, linux), true)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -ldl
- else ifeq ($(call isTargetOs, solaris), true)
- BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava -lsocket -lnsl
- BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -lthread -ldl
endif
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := -ljli
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := -ljvm
diff --git a/src/hotspot/.mx.jvmci/mx_jvmci.py b/src/hotspot/.mx.jvmci/mx_jvmci.py
index 9162cd16af8..9559a51e7ad 100644
--- a/src/hotspot/.mx.jvmci/mx_jvmci.py
+++ b/src/hotspot/.mx.jvmci/mx_jvmci.py
@@ -387,7 +387,7 @@ def _jvmci_gate_runner(args, tasks):
if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'fastdebug'])
with Task('CleanAndBuildIdealGraphVisualizer', tasks, disableJacoco=True) as t:
- if t and platform.processor() != 'sparc':
+ if t:
buildxml = mx._cygpathU2W(join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=_igvBuildEnv())
@@ -486,8 +486,6 @@ def hsdis(args, copyToDir=None):
flavor = 'intel'
if 'att' in args:
flavor = 'att'
- if mx.get_arch() == "sparcv9":
- flavor = "sparcv9"
lib = mx.add_lib_suffix('hsdis-' + mx.get_arch())
path = join(_suite.dir, 'lib', lib)
@@ -497,7 +495,6 @@ def hsdis(args, copyToDir=None):
'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30',
'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192',
'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2',
- 'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60',
}
flavoredLib = flavor + "/" + lib
@@ -579,8 +576,6 @@ def _get_openjdk_os():
os = 'macosx'
elif 'linux' in os:
os = 'linux'
- elif 'solaris' in os:
- os = 'solaris'
elif 'cygwin' in os or 'mingw' in os:
os = 'windows'
return os
@@ -589,8 +584,6 @@ def _get_openjdk_cpu():
cpu = mx.get_arch()
if cpu == 'amd64':
cpu = 'x86_64'
- elif cpu == 'sparcv9':
- cpu = 'sparcv9'
return cpu
def _get_openjdk_os_cpu():
diff --git a/src/hotspot/.mx.jvmci/suite.py b/src/hotspot/.mx.jvmci/suite.py
index e5eb37e5181..f0e1a85385d 100644
--- a/src/hotspot/.mx.jvmci/suite.py
+++ b/src/hotspot/.mx.jvmci/suite.py
@@ -87,7 +87,6 @@ suite = {
"dependencies" : [
"mx:JUNIT",
"jdk.vm.ci.amd64",
- "jdk.vm.ci.sparc",
"jdk.vm.ci.code",
"jdk.vm.ci.hotspot",
],
@@ -141,15 +140,6 @@ suite = {
"workingSets" : "JVMCI,AMD64",
},
- "jdk.vm.ci.sparc" : {
- "subDir" : "../jdk.internal.vm.ci/share/classes",
- "sourceDirs" : ["src"],
- "dependencies" : ["jdk.vm.ci.code"],
- "checkstyle" : "jdk.vm.ci.services",
- "javaCompliance" : "9+",
- "workingSets" : "JVMCI,SPARC",
- },
-
"jdk.vm.ci.hotspot" : {
"subDir" : "../jdk.internal.vm.ci/share/classes",
"sourceDirs" : ["src"],
@@ -205,18 +195,6 @@ suite = {
"workingSets" : "JVMCI,HotSpot,AMD64",
},
- "jdk.vm.ci.hotspot.sparc" : {
- "subDir" : "../jdk.internal.vm.ci/share/classes",
- "sourceDirs" : ["src"],
- "dependencies" : [
- "jdk.vm.ci.sparc",
- "jdk.vm.ci.hotspot",
- ],
- "checkstyle" : "jdk.vm.ci.services",
- "javaCompliance" : "9+",
- "workingSets" : "JVMCI,HotSpot,SPARC",
- },
-
"hotspot" : {
"native" : True,
"class" : "HotSpotProject",
@@ -239,7 +217,6 @@ suite = {
"jdk.vm.ci.common",
"jdk.vm.ci.aarch64",
"jdk.vm.ci.amd64",
- "jdk.vm.ci.sparc",
],
"distDependencies" : [
"JVMCI_SERVICES",
@@ -251,7 +228,6 @@ suite = {
"dependencies" : [
"jdk.vm.ci.hotspot.aarch64",
"jdk.vm.ci.hotspot.amd64",
- "jdk.vm.ci.hotspot.sparc",
],
"distDependencies" : [
"JVMCI_SERVICES",
diff --git a/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp b/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp
deleted file mode 100644
index 0363bcf0cdd..00000000000
--- a/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "interpreter/interpreter.hpp"
-#include "oops/constMethod.hpp"
-#include "oops/klass.inline.hpp"
-#include "oops/method.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/synchronizer.hpp"
-#include "utilities/align.hpp"
-#include "utilities/macros.hpp"
-
-
-int AbstractInterpreter::BasicType_as_index(BasicType type) {
- int i = 0;
- switch (type) {
- case T_BOOLEAN: i = 0; break;
- case T_CHAR : i = 1; break;
- case T_BYTE : i = 2; break;
- case T_SHORT : i = 3; break;
- case T_INT : i = 4; break;
- case T_LONG : i = 5; break;
- case T_VOID : i = 6; break;
- case T_FLOAT : i = 7; break;
- case T_DOUBLE : i = 8; break;
- case T_OBJECT : i = 9; break;
- case T_ARRAY : i = 9; break;
- default : ShouldNotReachHere();
- }
- assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
- return i;
-}
-
-static int size_activation_helper(int callee_extra_locals, int max_stack, int monitor_size) {
-
- // Figure out the size of an interpreter frame (in words) given that we have a fully allocated
- // expression stack, the callee will have callee_extra_locals (so we can account for
- // frame extension) and monitor_size for monitors. Basically we need to calculate
- // this exactly like generate_fixed_frame/generate_compute_interpreter_state.
- //
- //
- // The big complicating thing here is that we must ensure that the stack stays properly
- // aligned. This would be even uglier if monitor size wasn't modulo what the stack
- // needs to be aligned for). We are given that the sp (fp) is already aligned by
- // the caller so we must ensure that it is properly aligned for our callee.
- //
- const int rounded_vm_local_words =
- align_up((int)frame::interpreter_frame_vm_local_words,WordsPerLong);
- // callee_locals and max_stack are counts, not the size in frame.
- const int locals_size =
- align_up(callee_extra_locals * Interpreter::stackElementWords, WordsPerLong);
- const int max_stack_words = max_stack * Interpreter::stackElementWords;
- return (align_up((max_stack_words
- + rounded_vm_local_words
- + frame::memory_parameter_word_sp_offset), WordsPerLong)
- // already rounded
- + locals_size + monitor_size);
-}
-
-// How much stack a method top interpreter activation needs in words.
-int AbstractInterpreter::size_top_interpreter_activation(Method* method) {
-
- // See call_stub code
- int call_stub_size = align_up(7 + frame::memory_parameter_word_sp_offset,
- WordsPerLong); // 7 + register save area
-
- // Save space for one monitor to get into the interpreted method in case
- // the method is synchronized
- int monitor_size = method->is_synchronized() ?
- 1*frame::interpreter_frame_monitor_size() : 0;
- return size_activation_helper(method->max_locals(), method->max_stack(),
- monitor_size) + call_stub_size;
-}
-
-int AbstractInterpreter::size_activation(int max_stack,
- int temps,
- int extra_args,
- int monitors,
- int callee_params,
- int callee_locals,
- bool is_top_frame) {
- // Note: This calculation must exactly parallel the frame setup
- // in TemplateInterpreterGenerator::generate_fixed_frame.
-
- int monitor_size = monitors * frame::interpreter_frame_monitor_size();
-
- assert(is_aligned(monitor_size, WordsPerLong), "must align");
-
- //
- // Note: if you look closely this appears to be doing something much different
- // than generate_fixed_frame. What is happening is this. On sparc we have to do
- // this dance with interpreter_sp_adjustment because the window save area would
- // appear just below the bottom (tos) of the caller's java expression stack. Because
- // the interpreter want to have the locals completely contiguous generate_fixed_frame
- // will adjust the caller's sp for the "extra locals" (max_locals - parameter_size).
- // Now in generate_fixed_frame the extension of the caller's sp happens in the callee.
- // In this code the opposite occurs the caller adjusts it's own stack base on the callee.
- // This is mostly ok but it does cause a problem when we get to the initial frame (the oldest)
- // because the oldest frame would have adjust its callers frame and yet that frame
- // already exists and isn't part of this array of frames we are unpacking. So at first
- // glance this would seem to mess up that frame. However Deoptimization::fetch_unroll_info_helper()
- // will after it calculates all of the frame's on_stack_size()'s will then figure out the
- // amount to adjust the caller of the initial (oldest) frame and the calculation will all
- // add up. It does seem like it simpler to account for the adjustment here (and remove the
- // callee... parameters here). However this would mean that this routine would have to take
- // the caller frame as input so we could adjust its sp (and set it's interpreter_sp_adjustment)
- // and run the calling loop in the reverse order. This would also would appear to mean making
- // this code aware of what the interactions are when that initial caller fram was an osr or
- // other adapter frame. deoptimization is complicated enough and hard enough to debug that
- // there is no sense in messing working code.
- //
-
- int rounded_cls = align_up((callee_locals - callee_params), WordsPerLong);
- assert(is_aligned(rounded_cls, WordsPerLong), "must align");
-
- int raw_frame_size = size_activation_helper(rounded_cls, max_stack, monitor_size);
-
- return raw_frame_size;
-}
-
-void AbstractInterpreter::layout_activation(Method* method,
- int tempcount,
- int popframe_extra_args,
- int moncount,
- int caller_actual_parameters,
- int callee_param_count,
- int callee_local_count,
- frame* caller,
- frame* interpreter_frame,
- bool is_top_frame,
- bool is_bottom_frame) {
- // Set up the following variables:
- // - Lmethod
- // - Llocals
- // - Lmonitors (to the indicated number of monitors)
- // - Lesp (to the indicated number of temps)
- // The frame caller on entry is a description of the caller of the
- // frame we are about to layout. We are guaranteed that we will be
- // able to fill in a new interpreter frame as its callee (i.e. the
- // stack space is allocated and the amount was determined by an
- // earlier call to the size_activation() method). On return caller
- // while describe the interpreter frame we just layed out.
-
- // The skeleton frame must already look like an interpreter frame
- // even if not fully filled out.
- assert(interpreter_frame->is_interpreted_frame(), "Must be interpreted frame");
-
- int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words,WordsPerLong);
- int monitor_size = moncount * frame::interpreter_frame_monitor_size();
- assert(is_aligned(monitor_size, WordsPerLong), "must align");
-
- intptr_t* fp = interpreter_frame->fp();
-
- JavaThread* thread = JavaThread::current();
- RegisterMap map(thread, false);
- // More verification that skeleton frame is properly walkable
- assert(fp == caller->sp(), "fp must match");
-
- intptr_t* montop = fp - rounded_vm_local_words;
-
- // preallocate monitors (cf. __ add_monitor_to_stack)
- intptr_t* monitors = montop - monitor_size;
-
- // preallocate stack space
- intptr_t* esp = monitors - 1 -
- (tempcount * Interpreter::stackElementWords) -
- popframe_extra_args;
-
- int local_words = method->max_locals() * Interpreter::stackElementWords;
- NEEDS_CLEANUP;
- intptr_t* locals;
- if (caller->is_interpreted_frame()) {
- // Can force the locals area to end up properly overlapping the top of the expression stack.
- intptr_t* Lesp_ptr = caller->interpreter_frame_tos_address() - 1;
- // Note that this computation means we replace size_of_parameters() values from the caller
- // interpreter frame's expression stack with our argument locals
- int parm_words = caller_actual_parameters * Interpreter::stackElementWords;
- locals = Lesp_ptr + parm_words;
- int delta = local_words - parm_words;
- int computed_sp_adjustment = (delta > 0) ? align_up(delta, WordsPerLong) : 0;
- *interpreter_frame->register_addr(I5_savedSP) = (intptr_t) (fp + computed_sp_adjustment) - STACK_BIAS;
- if (!is_bottom_frame) {
- // Llast_SP is set below for the current frame to SP (with the
- // extra space for the callee's locals). Here we adjust
- // Llast_SP for the caller's frame, removing the extra space
- // for the current method's locals.
- *caller->register_addr(Llast_SP) = *interpreter_frame->register_addr(I5_savedSP);
- } else {
- assert(*caller->register_addr(Llast_SP) >= *interpreter_frame->register_addr(I5_savedSP), "strange Llast_SP");
- }
- } else {
- assert(caller->is_compiled_frame() || caller->is_entry_frame(), "only possible cases");
- // Don't have Lesp available; lay out locals block in the caller
- // adjacent to the register window save area.
- //
- // Compiled frames do not allocate a varargs area which is why this if
- // statement is needed.
- //
- if (caller->is_compiled_frame()) {
- locals = fp + frame::register_save_words + local_words - 1;
- } else {
- locals = fp + frame::memory_parameter_word_sp_offset + local_words - 1;
- }
- if (!caller->is_entry_frame()) {
- // Caller wants his own SP back
- int caller_frame_size = caller->cb()->frame_size();
- *interpreter_frame->register_addr(I5_savedSP) = (intptr_t)(caller->fp() - caller_frame_size) - STACK_BIAS;
- }
- }
- if (TraceDeoptimization) {
- if (caller->is_entry_frame()) {
- // make sure I5_savedSP and the entry frames notion of saved SP
- // agree. This assertion duplicate a check in entry frame code
- // but catches the failure earlier.
- assert(*caller->register_addr(Lscratch) == *interpreter_frame->register_addr(I5_savedSP),
- "would change callers SP");
- }
- if (caller->is_entry_frame()) {
- tty->print("entry ");
- }
- if (caller->is_compiled_frame()) {
- tty->print("compiled ");
- if (caller->is_deoptimized_frame()) {
- tty->print("(deopt) ");
- }
- }
- if (caller->is_interpreted_frame()) {
- tty->print("interpreted ");
- }
- tty->print_cr("caller fp=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, p2i(caller->fp()), p2i(caller->sp()));
- tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(caller->sp()), p2i(caller->sp() + 16));
- tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(caller->fp()), p2i(caller->fp() + 16));
- tty->print_cr("interpreter fp=" INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(interpreter_frame->fp()), p2i(interpreter_frame->sp()));
- tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(interpreter_frame->sp()), p2i(interpreter_frame->sp() + 16));
- tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(interpreter_frame->fp()), p2i(interpreter_frame->fp() + 16));
- tty->print_cr("Llocals = " INTPTR_FORMAT, p2i(locals));
- tty->print_cr("Lesp = " INTPTR_FORMAT, p2i(esp));
- tty->print_cr("Lmonitors = " INTPTR_FORMAT, p2i(monitors));
- }
-
- if (method->max_locals() > 0) {
- assert(locals < caller->sp() || locals >= (caller->sp() + 16), "locals in save area");
- assert(locals < caller->fp() || locals > (caller->fp() + 16), "locals in save area");
- assert(locals < interpreter_frame->sp() || locals > (interpreter_frame->sp() + 16), "locals in save area");
- assert(locals < interpreter_frame->fp() || locals >= (interpreter_frame->fp() + 16), "locals in save area");
- }
- assert(*interpreter_frame->register_addr(I5_savedSP) & 1, "must be odd");
-
- *interpreter_frame->register_addr(Lmethod) = (intptr_t) method;
- *interpreter_frame->register_addr(Llocals) = (intptr_t) locals;
- *interpreter_frame->register_addr(Lmonitors) = (intptr_t) monitors;
- *interpreter_frame->register_addr(Lesp) = (intptr_t) esp;
- // Llast_SP will be same as SP as there is no adapter space
- *interpreter_frame->register_addr(Llast_SP) = (intptr_t) interpreter_frame->sp() - STACK_BIAS;
- *interpreter_frame->register_addr(LcpoolCache) = (intptr_t) method->constants()->cache();
- // save the mirror in the interpreter frame
- *interpreter_frame->interpreter_frame_mirror_addr() = method->method_holder()->java_mirror();
-
-#ifdef ASSERT
- BasicObjectLock* mp = (BasicObjectLock*)monitors;
-
- assert(interpreter_frame->interpreter_frame_method() == method, "method matches");
- assert(interpreter_frame->interpreter_frame_local_at(9) == (intptr_t *)((intptr_t)locals - (9 * Interpreter::stackElementSize)), "locals match");
- assert(interpreter_frame->interpreter_frame_monitor_end() == mp, "monitor_end matches");
- assert(((intptr_t *)interpreter_frame->interpreter_frame_monitor_begin()) == ((intptr_t *)mp)+monitor_size, "monitor_begin matches");
- assert(interpreter_frame->interpreter_frame_tos_address()-1 == esp, "esp matches");
-
- // check bounds
- intptr_t* lo = interpreter_frame->sp() + (frame::memory_parameter_word_sp_offset - 1);
- intptr_t* hi = interpreter_frame->fp() - rounded_vm_local_words;
- assert(lo < monitors && montop <= hi, "monitors in bounds");
- assert(lo <= esp && esp < monitors, "esp in bounds");
-#endif // ASSERT
-}
diff --git a/src/hotspot/cpu/sparc/args.cc b/src/hotspot/cpu/sparc/args.cc
deleted file mode 100644
index 8459c8ae37c..00000000000
--- a/src/hotspot/cpu/sparc/args.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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
-#include
-
-static const int R_O0_num = 1000;
-static const int R_I0_num = 2000;
-static const int R_F0_num = 3000;
-static const int R_F1_num = R_F0_num + 1;
-static const int R_F2_num = R_F0_num + 2;
-static const int STACK_num= 4000;
-
-static bool LP64 = false;
-static bool LONGS_IN_ONE_ENTRY = false;
-
-static const int Op_RegI = 'I';
-static const int Op_RegP = 'P';
-static const int Op_RegF = 'F';
-static const int Op_RegD = 'D';
-static const int Op_RegL = 'L';
-static const int SPARC_ARGS_IN_REGS_NUM=6;
-
-static void print_reg( int reg ) {
- if( reg == 0 )
- printf("__"); // halve's
- else if( reg >= STACK_num && reg < STACK_num+100 )
- printf("S%d_",reg - STACK_num);
- else if( reg >= R_F0_num && reg < R_F0_num+100 )
- printf("F%d_",reg - R_F0_num);
- else if( reg >= R_O0_num && reg < R_O0_num+100 ) {
- if( LONGS_IN_ONE_ENTRY ) {
- reg -= R_O0_num;
- printf("O%d",reg>>1);
- printf(reg&1 ? "H" : "L");
- } else
- printf("O%d_",reg - R_O0_num);
- } else
- printf("Wretched: %d\n", reg);
-}
-
-static void print_convention( int *sig, const char *s, int length ) {
- // Print it out
- for( int i = 0; i < length; i++) {
- if( sig[i] == 0 ) continue; // do not print 'halves'
- print_reg( sig[i] & 0xFFFF );
- int reg = sig[i] >> 16;
- if( reg ) {
- printf(":");
- print_reg( reg );
- } else {
- printf(" ");
- }
- printf(" ");
- }
- printf("\n");
-}
-
-static int INT_SCALE( int x ) {
- return LONGS_IN_ONE_ENTRY ? (x<<1) : x;
-}
-
-static void java_convention( int *sig, const char *s, int length ) {
- if( LP64 && !LONGS_IN_ONE_ENTRY ) {
- printf("LP64 and 2-reg longs not supported\n");
- return;
- }
- for( int i = 0; i < length; i++ )
- sig[i] = s[i]; // Reset sig array
- bool is_outgoing = true;
-
- int int_base = (is_outgoing ? R_O0_num : R_I0_num);
-
- // Convention is to pack the first 6 int/oop args into the first 6
- // registers (I0-I5), extras spill to the stack. Then pack the first
- // 32 float args into F0-F31, extras spill to the stack. Then pad
- // all register sets to align. Then put longs and doubles into the
- // same registers as they fit, else spill to the stack.
- int int_reg_max = SPARC_ARGS_IN_REGS_NUM;
- int flt_reg_max = 32;
-
- // Count int/oop and float args. See how many stack slots we'll need
- // and where the longs & doubles will go.
- int int_reg_cnt = 0;
- int flt_reg_cnt = 0;
- int stk_reg_pairs = 0;
- for( int i = 0; i < length; i++) {
- switch( sig[i] ) {
- case Op_RegL: // Longs-in-1-reg compete with int args
- if( LONGS_IN_ONE_ENTRY ) {
- if( int_reg_cnt < int_reg_max ) int_reg_cnt++;
- }
- break;
- case Op_RegP:
- if( int_reg_cnt < int_reg_max ) int_reg_cnt++;
- else if( !LP64 ) stk_reg_pairs++;
- break;
- case Op_RegI:
- if( int_reg_cnt < int_reg_max ) int_reg_cnt++;
- else stk_reg_pairs++;
- break;
- case Op_RegF:
- if( flt_reg_cnt < flt_reg_max ) flt_reg_cnt++;
- else stk_reg_pairs++;
- break;
- }
- }
-
- // This is where the longs/doubles start on the stack.
- stk_reg_pairs = (stk_reg_pairs+1) & ~1; // Round
-
- int int_reg_pairs = (int_reg_cnt+1) & ~1; // 32-bit 2-reg longs only
- int flt_reg_pairs = (flt_reg_cnt+1) & ~1;
-
- int stk_reg = 0;
- int int_reg = 0;
- int flt_reg = 0;
-
- // Now do the signature layout
- for( int i = 0; i < length; i++) {
- int tmp = sig[i];
- if( tmp == Op_RegP )
- tmp = LP64 ? Op_RegL : Op_RegI; // Treat ptrs and ints or long accordingly
- switch( tmp ) {
- case Op_RegI:
-// case Op_RegP:
- if( int_reg < int_reg_max) tmp = INT_SCALE(int_reg++) + int_base;
- else tmp = STACK_num + stk_reg++;
- sig[i] = tmp;
- break;
-
- case Op_RegL:
- if( sig[i] != Op_RegP && sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; }
-// case Op_RegP:
- if( LONGS_IN_ONE_ENTRY ) {
- if( int_reg < int_reg_max ) {
- tmp = INT_SCALE(int_reg++) + int_base;
- } else {
- tmp = STACK_num + stk_reg_pairs;
- stk_reg_pairs += 2;
- }
- } else {
- if( int_reg_pairs < int_reg_max ) {
- tmp = int_reg_pairs + int_base;
- int_reg_pairs += 2;
- } else {
- tmp = STACK_num + stk_reg_pairs;
- stk_reg_pairs += 2;
- }
- }
- sig[i] = tmp | (tmp+1)<<16; // Smear to pair
- break;
-
- case Op_RegF:
- sig[i] = (flt_reg < flt_reg_max) ? (R_F0_num + flt_reg++) : STACK_num + stk_reg++;
- break;
- case Op_RegD:
- if( sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; }
- if( flt_reg_pairs < flt_reg_max ) {
- tmp = R_F0_num + flt_reg_pairs;
- flt_reg_pairs += 2;
- } else {
- tmp = STACK_num + stk_reg_pairs;
- stk_reg_pairs += 2;
- }
- sig[i] = tmp | (tmp+1)<<16; // Smear to pair
- break;
- case 'h': sig[i] = 0; break;
- default:
- printf("Bad character: %c\n", sig[i] );
- return;
- }
- }
-
- printf("java ");
- printf(LP64 ? "LP64 " : "LP32 ");
- printf(LONGS_IN_ONE_ENTRY ? "long1: " : "long2: ");
- print_convention(sig,s,length);
-}
-
-static int int_stk_helper( int i ) {
- if( i < 6 ) return R_O0_num + (LONGS_IN_ONE_ENTRY ? i<<1 : i);
- else return STACK_num + (LP64 ? i<<1 : i);
-}
-
-static void native_convention( int *sig, const char *s, int length ) {
- if( LP64 && !LONGS_IN_ONE_ENTRY ) {
- printf("LP64 and 2-reg longs not supported\n");
- return;
- }
- for( int i = 0; i < length; i++ )
- sig[i] = s[i]; // Reset sig array
-
- // The native convention is V8 if !LP64, which means the V8 convention is
- // used both with and without LONGS_IN_ONE_ENTRY, an unfortunate split. The
- // same actual machine registers are used, but they are named differently in
- // the LONGS_IN_ONE_ENTRY mode. The LP64 convention is the V9 convention
- // which is slightly more sane.
-
- if( LP64 ) {
- // V9 convention: All things "as-if" on double-wide stack slots.
- // Hoist any int/ptr/long's in the first 6 to int regs.
- // Hoist any flt/dbl's in the first 16 dbl regs.
- int j = 0; // Count of actual args, not HALVES
- for( int i=0; istart();
- address addrN = csect->end();
- uint32_t prev = 0;
-
- assert((addrN - addr0) % BytesPerInstWord == 0, "must be");
-
- for (address pc = addr0; pc != addrN; pc += BytesPerInstWord) {
- uint32_t insn = *reinterpret_cast(pc);
-
- // 1. General case: No CTI immediately after other CTI
- assert(!(is_cti(prev) && is_cti(insn)), "CTI-CTI not allowed.");
-
- // 2. Special case: No CTI immediately after/before RDPC
- assert(!(is_cti(prev) && is_rdpc(insn)), "CTI-RDPC not allowed.");
- assert(!(is_rdpc(prev) && is_cti(insn)), "RDPC-CTI not allowed.");
-
- prev = insn;
- }
-}
-#endif
diff --git a/src/hotspot/cpu/sparc/assembler_sparc.hpp b/src/hotspot/cpu/sparc/assembler_sparc.hpp
deleted file mode 100644
index cefc0b248e8..00000000000
--- a/src/hotspot/cpu/sparc/assembler_sparc.hpp
+++ /dev/null
@@ -1,1339 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_ASSEMBLER_SPARC_HPP
-#define CPU_SPARC_ASSEMBLER_SPARC_HPP
-
-#include "asm/register.hpp"
-
-// The SPARC Assembler: Pure assembler doing NO optimizations on the instruction
-// level; i.e., what you write is what you get. The Assembler is generating code
-// into a CodeBuffer.
-
-class Assembler : public AbstractAssembler {
- friend class AbstractAssembler;
- friend class AddressLiteral;
-
- // code patchers need various routines like inv_wdisp()
- friend class NativeInstruction;
- friend class NativeGeneralJump;
- friend class Relocation;
- friend class Label;
-
- public:
- // op carries format info; see page 62 & 267
-
- enum ops {
- call_op = 1, // fmt 1
- branch_op = 0, // also sethi (fmt2)
- arith_op = 2, // fmt 3, arith & misc
- ldst_op = 3 // fmt 3, load/store
- };
-
- enum op2s {
- bpr_op2 = 3,
- fb_op2 = 6,
- fbp_op2 = 5,
- br_op2 = 2,
- bp_op2 = 1,
- sethi_op2 = 4
- };
-
- enum op3s {
- // selected op3s
- add_op3 = 0x00,
- and_op3 = 0x01,
- or_op3 = 0x02,
- xor_op3 = 0x03,
- sub_op3 = 0x04,
- andn_op3 = 0x05,
- orn_op3 = 0x06,
- xnor_op3 = 0x07,
- addc_op3 = 0x08,
- mulx_op3 = 0x09,
- umul_op3 = 0x0a,
- smul_op3 = 0x0b,
- subc_op3 = 0x0c,
- udivx_op3 = 0x0d,
- udiv_op3 = 0x0e,
- sdiv_op3 = 0x0f,
-
- addcc_op3 = 0x10,
- andcc_op3 = 0x11,
- orcc_op3 = 0x12,
- xorcc_op3 = 0x13,
- subcc_op3 = 0x14,
- andncc_op3 = 0x15,
- orncc_op3 = 0x16,
- xnorcc_op3 = 0x17,
- addccc_op3 = 0x18,
- aes4_op3 = 0x19,
- umulcc_op3 = 0x1a,
- smulcc_op3 = 0x1b,
- subccc_op3 = 0x1c,
- udivcc_op3 = 0x1e,
- sdivcc_op3 = 0x1f,
-
- taddcc_op3 = 0x20,
- tsubcc_op3 = 0x21,
- taddcctv_op3 = 0x22,
- tsubcctv_op3 = 0x23,
- mulscc_op3 = 0x24,
- sll_op3 = 0x25,
- sllx_op3 = 0x25,
- srl_op3 = 0x26,
- srlx_op3 = 0x26,
- sra_op3 = 0x27,
- srax_op3 = 0x27,
- rdreg_op3 = 0x28,
- membar_op3 = 0x28,
-
- flushw_op3 = 0x2b,
- movcc_op3 = 0x2c,
- sdivx_op3 = 0x2d,
- popc_op3 = 0x2e,
- movr_op3 = 0x2f,
-
- sir_op3 = 0x30,
- wrreg_op3 = 0x30,
- saved_op3 = 0x31,
-
- fpop1_op3 = 0x34,
- fpop2_op3 = 0x35,
- impdep1_op3 = 0x36,
- addx_op3 = 0x36,
- aes3_op3 = 0x36,
- sha_op3 = 0x36,
- bmask_op3 = 0x36,
- bshuffle_op3 = 0x36,
- alignaddr_op3 = 0x36,
- faligndata_op3 = 0x36,
- flog3_op3 = 0x36,
- edge_op3 = 0x36,
- fzero_op3 = 0x36,
- fsrc_op3 = 0x36,
- fnot_op3 = 0x36,
- mpmul_op3 = 0x36,
- umulx_op3 = 0x36,
- xmulx_op3 = 0x36,
- crc32c_op3 = 0x36,
- impdep2_op3 = 0x37,
- stpartialf_op3 = 0x37,
- jmpl_op3 = 0x38,
- rett_op3 = 0x39,
- trap_op3 = 0x3a,
- flush_op3 = 0x3b,
- save_op3 = 0x3c,
- restore_op3 = 0x3d,
- done_op3 = 0x3e,
- retry_op3 = 0x3e,
-
- lduw_op3 = 0x00,
- ldub_op3 = 0x01,
- lduh_op3 = 0x02,
- ldd_op3 = 0x03,
- stw_op3 = 0x04,
- stb_op3 = 0x05,
- sth_op3 = 0x06,
- std_op3 = 0x07,
- ldsw_op3 = 0x08,
- ldsb_op3 = 0x09,
- ldsh_op3 = 0x0a,
- ldx_op3 = 0x0b,
-
- stx_op3 = 0x0e,
- swap_op3 = 0x0f,
-
- stwa_op3 = 0x14,
- stxa_op3 = 0x1e,
-
- ldf_op3 = 0x20,
- ldfsr_op3 = 0x21,
- ldqf_op3 = 0x22,
- lddf_op3 = 0x23,
- stf_op3 = 0x24,
- stfsr_op3 = 0x25,
- stqf_op3 = 0x26,
- stdf_op3 = 0x27,
-
- prefetch_op3 = 0x2d,
-
- casa_op3 = 0x3c,
- casxa_op3 = 0x3e,
-
- mftoi_op3 = 0x36,
-
- alt_bit_op3 = 0x10,
- cc_bit_op3 = 0x10
- };
-
- enum opfs {
- // selected opfs
- edge8n_opf = 0x01,
-
- fmovs_opf = 0x01,
- fmovd_opf = 0x02,
-
- fnegs_opf = 0x05,
- fnegd_opf = 0x06,
-
- addxc_opf = 0x11,
- addxccc_opf = 0x13,
- umulxhi_opf = 0x16,
- alignaddr_opf = 0x18,
- bmask_opf = 0x19,
-
- fadds_opf = 0x41,
- faddd_opf = 0x42,
- fsubs_opf = 0x45,
- fsubd_opf = 0x46,
-
- faligndata_opf = 0x48,
-
- fmuls_opf = 0x49,
- fmuld_opf = 0x4a,
- bshuffle_opf = 0x4c,
- fdivs_opf = 0x4d,
- fdivd_opf = 0x4e,
-
- fcmps_opf = 0x51,
- fcmpd_opf = 0x52,
-
- fstox_opf = 0x81,
- fdtox_opf = 0x82,
- fxtos_opf = 0x84,
- fxtod_opf = 0x88,
- fitos_opf = 0xc4,
- fdtos_opf = 0xc6,
- fitod_opf = 0xc8,
- fstod_opf = 0xc9,
- fstoi_opf = 0xd1,
- fdtoi_opf = 0xd2,
-
- mdtox_opf = 0x110,
- mstouw_opf = 0x111,
- mstosw_opf = 0x113,
- xmulx_opf = 0x115,
- xmulxhi_opf = 0x116,
- mxtod_opf = 0x118,
- mwtos_opf = 0x119,
-
- aes_kexpand0_opf = 0x130,
- aes_kexpand2_opf = 0x131,
-
- sha1_opf = 0x141,
- sha256_opf = 0x142,
- sha512_opf = 0x143,
-
- crc32c_opf = 0x147,
- mpmul_opf = 0x148
- };
-
- enum op5s {
- aes_eround01_op5 = 0x00,
- aes_eround23_op5 = 0x01,
- aes_dround01_op5 = 0x02,
- aes_dround23_op5 = 0x03,
- aes_eround01_l_op5 = 0x04,
- aes_eround23_l_op5 = 0x05,
- aes_dround01_l_op5 = 0x06,
- aes_dround23_l_op5 = 0x07,
- aes_kexpand1_op5 = 0x08
- };
-
- enum RCondition { rc_z = 1, rc_lez = 2, rc_lz = 3, rc_nz = 5, rc_gz = 6, rc_gez = 7, rc_last = rc_gez };
-
- enum Condition {
- // for FBfcc & FBPfcc instruction
- f_never = 0,
- f_notEqual = 1,
- f_notZero = 1,
- f_lessOrGreater = 2,
- f_unorderedOrLess = 3,
- f_less = 4,
- f_unorderedOrGreater = 5,
- f_greater = 6,
- f_unordered = 7,
- f_always = 8,
- f_equal = 9,
- f_zero = 9,
- f_unorderedOrEqual = 10,
- f_greaterOrEqual = 11,
- f_unorderedOrGreaterOrEqual = 12,
- f_lessOrEqual = 13,
- f_unorderedOrLessOrEqual = 14,
- f_ordered = 15,
-
- // for integers
-
- never = 0,
- equal = 1,
- zero = 1,
- lessEqual = 2,
- less = 3,
- lessEqualUnsigned = 4,
- lessUnsigned = 5,
- carrySet = 5,
- negative = 6,
- overflowSet = 7,
- always = 8,
- notEqual = 9,
- notZero = 9,
- greater = 10,
- greaterEqual = 11,
- greaterUnsigned = 12,
- greaterEqualUnsigned = 13,
- carryClear = 13,
- positive = 14,
- overflowClear = 15
- };
-
- enum CC {
- // ptr_cc is the correct condition code for a pointer or intptr_t:
- icc = 0, xcc = 2, ptr_cc = xcc,
- fcc0 = 0, fcc1 = 1, fcc2 = 2, fcc3 = 3
- };
-
- enum PrefetchFcn {
- severalReads = 0, oneRead = 1, severalWritesAndPossiblyReads = 2, oneWrite = 3, page = 4
- };
-
- public:
- // Helper functions for groups of instructions
-
- enum Predict { pt = 1, pn = 0 }; // pt = predict taken
-
- enum Membar_mask_bits { // page 184, v9
- StoreStore = 1 << 3,
- LoadStore = 1 << 2,
- StoreLoad = 1 << 1,
- LoadLoad = 1 << 0,
-
- Sync = 1 << 6,
- MemIssue = 1 << 5,
- Lookaside = 1 << 4
- };
-
- //---< calculate length of instruction >---
- // With SPARC being a RISC architecture, this always is BytesPerInstWord
- // instruction must start at passed address
- static unsigned int instr_len(unsigned char *instr) { return BytesPerInstWord; }
-
- //---< longest instructions >---
- static unsigned int instr_maxlen() { return BytesPerInstWord; }
-
- static bool is_in_wdisp_range(address a, address b, int nbits) {
- intptr_t d = intptr_t(b) - intptr_t(a);
- return is_simm(d, nbits + 2);
- }
-
- address target_distance(Label &L) {
- // Assembler::target(L) should be called only when
- // a branch instruction is emitted since non-bound
- // labels record current pc() as a branch address.
- if (L.is_bound()) return target(L);
- // Return current address for non-bound labels.
- return pc();
- }
-
- // test if label is in simm16 range in words (wdisp16).
- bool is_in_wdisp16_range(Label &L) {
- return is_in_wdisp_range(target_distance(L), pc(), 16);
- }
- // test if the distance between two addresses fits in simm30 range in words
- static bool is_in_wdisp30_range(address a, address b) {
- return is_in_wdisp_range(a, b, 30);
- }
-
- enum ASIs { // page 72, v9
- ASI_PRIMARY = 0x80,
- ASI_PRIMARY_NOFAULT = 0x82,
- ASI_PRIMARY_LITTLE = 0x88,
- // 8x8-bit partial store
- ASI_PST8_PRIMARY = 0xC0,
- // Block initializing store
- ASI_ST_BLKINIT_PRIMARY = 0xE2,
- // Most-Recently-Used (MRU) BIS variant
- ASI_ST_BLKINIT_MRU_PRIMARY = 0xF2
- // add more from book as needed
- };
-
- protected:
- // helpers
-
- // x is supposed to fit in a field "nbits" wide
- // and be sign-extended. Check the range.
-
- static void assert_signed_range(intptr_t x, int nbits) {
- assert(nbits == 32 || (-(1 << nbits-1) <= x && x < (1 << nbits-1)),
- "value out of range: x=" INTPTR_FORMAT ", nbits=%d", x, nbits);
- }
-
- static void assert_signed_word_disp_range(intptr_t x, int nbits) {
- assert((x & 3) == 0, "not word aligned");
- assert_signed_range(x, nbits + 2);
- }
-
- static void assert_unsigned_range(int x, int nbits) {
- assert(juint(x) < juint(1 << nbits), "unsigned constant out of range");
- }
-
- // fields: note bits numbered from LSB = 0, fields known by inclusive bit range
-
- static int fmask(juint hi_bit, juint lo_bit) {
- assert(hi_bit >= lo_bit && 0 <= lo_bit && hi_bit < 32, "bad bits");
- return (1 << (hi_bit-lo_bit + 1)) - 1;
- }
-
- // inverse of u_field
-
- static int inv_u_field(int x, int hi_bit, int lo_bit) {
- juint r = juint(x) >> lo_bit;
- r &= fmask(hi_bit, lo_bit);
- return int(r);
- }
-
- // signed version: extract from field and sign-extend
-
- static int inv_s_field(int x, int hi_bit, int lo_bit) {
- int sign_shift = 31 - hi_bit;
- return inv_u_field(((x << sign_shift) >> sign_shift), hi_bit, lo_bit);
- }
-
- // given a field that ranges from hi_bit to lo_bit (inclusive,
- // LSB = 0), and an unsigned value for the field,
- // shift it into the field
-
-#ifdef ASSERT
- static int u_field(int x, int hi_bit, int lo_bit) {
- assert((x & ~fmask(hi_bit, lo_bit)) == 0,
- "value out of range");
- int r = x << lo_bit;
- assert(inv_u_field(r, hi_bit, lo_bit) == x, "just checking");
- return r;
- }
-#else
- // make sure this is inlined as it will reduce code size significantly
- #define u_field(x, hi_bit, lo_bit) ((x) << (lo_bit))
-#endif
-
- static int inv_op(int x) { return inv_u_field(x, 31, 30); }
- static int inv_op2(int x) { return inv_u_field(x, 24, 22); }
- static int inv_op3(int x) { return inv_u_field(x, 24, 19); }
- static int inv_cond(int x) { return inv_u_field(x, 28, 25); }
-
- static bool inv_immed(int x) { return (x & Assembler::immed(true)) != 0; }
-
- static Register inv_rd(int x) { return as_Register(inv_u_field(x, 29, 25)); }
- static Register inv_rs1(int x) { return as_Register(inv_u_field(x, 18, 14)); }
- static Register inv_rs2(int x) { return as_Register(inv_u_field(x, 4, 0)); }
-
- static int op(int x) { return u_field(x, 31, 30); }
- static int rd(Register r) { return u_field(r->encoding(), 29, 25); }
- static int fcn(int x) { return u_field(x, 29, 25); }
- static int op3(int x) { return u_field(x, 24, 19); }
- static int rs1(Register r) { return u_field(r->encoding(), 18, 14); }
- static int rs2(Register r) { return u_field(r->encoding(), 4, 0); }
- static int annul(bool a) { return u_field(a ? 1 : 0, 29, 29); }
- static int cond(int x) { return u_field(x, 28, 25); }
- static int cond_mov(int x) { return u_field(x, 17, 14); }
- static int rcond(RCondition x) { return u_field(x, 12, 10); }
- static int op2(int x) { return u_field(x, 24, 22); }
- static int predict(bool p) { return u_field(p ? 1 : 0, 19, 19); }
- static int branchcc(CC fcca) { return u_field(fcca, 21, 20); }
- static int cmpcc(CC fcca) { return u_field(fcca, 26, 25); }
- static int imm_asi(int x) { return u_field(x, 12, 5); }
- static int immed(bool i) { return u_field(i ? 1 : 0, 13, 13); }
- static int opf_low6(int w) { return u_field(w, 10, 5); }
- static int opf_low5(int w) { return u_field(w, 9, 5); }
- static int op5(int x) { return u_field(x, 8, 5); }
- static int trapcc(CC cc) { return u_field(cc, 12, 11); }
- static int sx(int i) { return u_field(i, 12, 12); } // shift x=1 means 64-bit
- static int opf(int x) { return u_field(x, 13, 5); }
-
- static bool is_cbcond(int x) {
- return (VM_Version::has_cbcond() && (inv_cond(x) > rc_last) &&
- inv_op(x) == branch_op && inv_op2(x) == bpr_op2);
- }
- static bool is_cxb(int x) {
- assert(is_cbcond(x), "wrong instruction");
- return (x & (1 << 21)) != 0;
- }
- static bool is_branch(int x) {
- if (inv_op(x) != Assembler::branch_op) return false;
-
- bool is_bpr = inv_op2(x) == Assembler::bpr_op2;
- bool is_bp = inv_op2(x) == Assembler::bp_op2;
- bool is_br = inv_op2(x) == Assembler::br_op2;
- bool is_fp = inv_op2(x) == Assembler::fb_op2;
- bool is_fbp = inv_op2(x) == Assembler::fbp_op2;
-
- return is_bpr || is_bp || is_br || is_fp || is_fbp;
- }
- static bool is_call(int x) {
- return inv_op(x) == Assembler::call_op;
- }
- static bool is_jump(int x) {
- if (inv_op(x) != Assembler::arith_op) return false;
-
- bool is_jmpl = inv_op3(x) == Assembler::jmpl_op3;
- bool is_rett = inv_op3(x) == Assembler::rett_op3;
-
- return is_jmpl || is_rett;
- }
- static bool is_rdpc(int x) {
- return (inv_op(x) == Assembler::arith_op && inv_op3(x) == Assembler::rdreg_op3 &&
- inv_u_field(x, 18, 14) == 5);
- }
- static bool is_cti(int x) {
- return is_branch(x) || is_call(x) || is_jump(x); // Ignoring done/retry
- }
-
- static int cond_cbcond(int x) { return u_field((((x & 8) << 1) + 8 + (x & 7)), 29, 25); }
- static int inv_cond_cbcond(int x) {
- assert(is_cbcond(x), "wrong instruction");
- return inv_u_field(x, 27, 25) | (inv_u_field(x, 29, 29) << 3);
- }
-
- static int opf_cc(CC c, bool useFloat) { return u_field((useFloat ? 0 : 4) + c, 13, 11); }
- static int mov_cc(CC c, bool useFloat) { return u_field(useFloat ? 0 : 1, 18, 18) | u_field(c, 12, 11); }
-
- static int fd(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 29, 25); };
- static int fs1(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 18, 14); };
- static int fs2(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 4, 0); };
- static int fs3(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 13, 9); };
-
- // some float instructions use this encoding on the op3 field
- static int alt_op3(int op, FloatRegisterImpl::Width w) {
- int r;
- switch(w) {
- case FloatRegisterImpl::S: r = op + 0; break;
- case FloatRegisterImpl::D: r = op + 3; break;
- case FloatRegisterImpl::Q: r = op + 2; break;
- default: ShouldNotReachHere(); break;
- }
- return op3(r);
- }
-
- // compute inverse of simm
- static int inv_simm(int x, int nbits) {
- return (int)(x << (32 - nbits)) >> (32 - nbits);
- }
-
- static int inv_simm13(int x) { return inv_simm(x, 13); }
-
- // signed immediate, in low bits, nbits long
- static int simm(int x, int nbits) {
- assert_signed_range(x, nbits);
- return x & ((1 << nbits) - 1);
- }
-
- // unsigned immediate, in low bits, at most nbits long.
- static int uimm(int x, int nbits) {
- assert_unsigned_range(x, nbits);
- return x & ((1 << nbits) - 1);
- }
-
- // compute inverse of wdisp16
- static intptr_t inv_wdisp16(int x, intptr_t pos) {
- int lo = x & ((1 << 14) - 1);
- int hi = (x >> 20) & 3;
- if (hi >= 2) hi |= ~1;
- return (((hi << 14) | lo) << 2) + pos;
- }
-
- // word offset, 14 bits at LSend, 2 bits at B21, B20
- static int wdisp16(intptr_t x, intptr_t off) {
- intptr_t xx = x - off;
- assert_signed_word_disp_range(xx, 16);
- int r = (xx >> 2) & ((1 << 14) - 1) | (((xx >> (2+14)) & 3) << 20);
- assert(inv_wdisp16(r, off) == x, "inverse is not inverse");
- return r;
- }
-
- // compute inverse of wdisp10
- static intptr_t inv_wdisp10(int x, intptr_t pos) {
- assert(is_cbcond(x), "wrong instruction");
- int lo = inv_u_field(x, 12, 5);
- int hi = (x >> 19) & 3;
- if (hi >= 2) hi |= ~1;
- return (((hi << 8) | lo) << 2) + pos;
- }
-
- // word offset for cbcond, 8 bits at [B12,B5], 2 bits at [B20,B19]
- static int wdisp10(intptr_t x, intptr_t off) {
- assert(VM_Version::has_cbcond(), "This CPU does not have CBCOND instruction");
- intptr_t xx = x - off;
- assert_signed_word_disp_range(xx, 10);
- int r = (((xx >> 2) & ((1 << 8) - 1)) << 5) | (((xx >> (2+8)) & 3) << 19);
- // Have to fake cbcond instruction to pass assert in inv_wdisp10()
- assert(inv_wdisp10((r | op(branch_op) | cond_cbcond(rc_last+1) | op2(bpr_op2)), off) == x, "inverse is not inverse");
- return r;
- }
-
- // word displacement in low-order nbits bits
-
- static intptr_t inv_wdisp(int x, intptr_t pos, int nbits) {
- int pre_sign_extend = x & ((1 << nbits) - 1);
- int r = (pre_sign_extend >= (1 << (nbits - 1)) ?
- pre_sign_extend | ~((1 << nbits) - 1) : pre_sign_extend);
- return (r << 2) + pos;
- }
-
- static int wdisp(intptr_t x, intptr_t off, int nbits) {
- intptr_t xx = x - off;
- assert_signed_word_disp_range(xx, nbits);
- int r = (xx >> 2) & ((1 << nbits) - 1);
- assert(inv_wdisp(r, off, nbits) == x, "inverse not inverse");
- return r;
- }
-
-
- // Extract the top 32 bits in a 64 bit word
- static int32_t hi32(int64_t x) {
- int32_t r = int32_t((uint64_t)x >> 32);
- return r;
- }
-
- // given a sethi instruction, extract the constant, left-justified
- static int inv_hi22(int x) {
- return x << 10;
- }
-
- // create an imm22 field, given a 32-bit left-justified constant
- static int hi22(int x) {
- int r = int(juint(x) >> 10);
- assert((r & ~((1 << 22) - 1)) == 0, "just checkin'");
- return r;
- }
-
- // create a low10 __value__ (not a field) for a given a 32-bit constant
- static int low10(int x) {
- return x & ((1 << 10) - 1);
- }
-
- // create a low12 __value__ (not a field) for a given a 32-bit constant
- static int low12(int x) {
- return x & ((1 << 12) - 1);
- }
-
- // AES crypto instructions supported only on certain processors
- static void aes_only() { assert(VM_Version::has_aes(), "This instruction only works on SPARC with AES instructions support"); }
-
- // SHA crypto instructions supported only on certain processors
- static void sha1_only() { assert(VM_Version::has_sha1(), "This instruction only works on SPARC with SHA1"); }
- static void sha256_only() { assert(VM_Version::has_sha256(), "This instruction only works on SPARC with SHA256"); }
- static void sha512_only() { assert(VM_Version::has_sha512(), "This instruction only works on SPARC with SHA512"); }
-
- // CRC32C instruction supported only on certain processors
- static void crc32c_only() { assert(VM_Version::has_crc32c(), "This instruction only works on SPARC with CRC32C"); }
-
- // FMAf instructions supported only on certain processors
- static void fmaf_only() { assert(VM_Version::has_fmaf(), "This instruction only works on SPARC with FMAf"); }
-
- // MPMUL instruction supported only on certain processors
- static void mpmul_only() { assert(VM_Version::has_mpmul(), "This instruction only works on SPARC with MPMUL"); }
-
- // instruction only in VIS1
- static void vis1_only() { assert(VM_Version::has_vis1(), "This instruction only works on SPARC with VIS1"); }
-
- // instruction only in VIS2
- static void vis2_only() { assert(VM_Version::has_vis2(), "This instruction only works on SPARC with VIS2"); }
-
- // instruction only in VIS3
- static void vis3_only() { assert(VM_Version::has_vis3(), "This instruction only works on SPARC with VIS3"); }
-
- // instruction deprecated in v9
- static void v9_dep() { } // do nothing for now
-
- protected:
-#ifdef ASSERT
-#define VALIDATE_PIPELINE
-#endif
-
-#ifdef VALIDATE_PIPELINE
- // A simple delay-slot scheme:
- // In order to check the programmer, the assembler keeps track of delay-slots.
- // It forbids CTIs in delay-slots (conservative, but should be OK). Also, when
- // emitting an instruction into a delay-slot, you must do so using delayed(),
- // e.g. asm->delayed()->add(...), in order to check that you do not omit the
- // delay-slot instruction. To implement this, we use a simple FSA.
- enum { NoDelay, AtDelay, FillDelay } _delay_state;
-
- // A simple hazard scheme:
- // In order to avoid pipeline stalls, due to single cycle pipeline hazards, we
- // adopt a simplistic state tracking mechanism that will enforce an additional
- // 'nop' instruction to be inserted prior to emitting an instruction that can
- // expose a given hazard (currently, PC-related hazards only).
- enum { NoHazard, PcHazard } _hazard_state;
-#endif
-
- public:
- // Tell the assembler that the next instruction must NOT be in delay-slot.
- // Use at start of multi-instruction macros.
- void assert_not_delayed() {
- // This is a separate entry to avoid the creation of string constants in
- // non-asserted code, with some compilers this pollutes the object code.
-#ifdef VALIDATE_PIPELINE
- assert_no_delay("Next instruction should not be in a delay-slot.");
-#endif
- }
-
- protected:
- void assert_no_delay(const char* msg) {
-#ifdef VALIDATE_PIPELINE
- assert(_delay_state == NoDelay, msg);
-#endif
- }
-
- void assert_no_hazard() {
-#ifdef VALIDATE_PIPELINE
- assert(_hazard_state == NoHazard, "Unsolicited pipeline hazard.");
-#endif
- }
-
- private:
- inline int32_t prev_insn() {
- assert(offset() > 0, "Interface violation.");
- int32_t* addr = (int32_t*)pc() - 1;
- return *addr;
- }
-
-#ifdef VALIDATE_PIPELINE
- void validate_no_pipeline_hazards();
-#endif
-
- protected:
- // Avoid possible pipeline stall by inserting an additional 'nop' instruction,
- // if the previous instruction is a 'cbcond' or a 'rdpc'.
- inline void avoid_pipeline_stall();
-
- // A call to cti() is made before emitting a control-transfer instruction (CTI)
- // in order to assert a CTI is not emitted right after a 'cbcond', nor in the
- // delay-slot of another CTI. Only effective when assertions are enabled.
- void cti() {
- // A 'cbcond' or 'rdpc' instruction immediately followed by a CTI introduces
- // a pipeline stall, which we make sure to prohibit.
- assert_no_cbcond_before();
- assert_no_rdpc_before();
-#ifdef VALIDATE_PIPELINE
- assert_no_hazard();
- assert_no_delay("CTI in delay-slot.");
-#endif
- }
-
- // Called when emitting CTI with a delay-slot, AFTER emitting.
- inline void induce_delay_slot() {
-#ifdef VALIDATE_PIPELINE
- assert_no_delay("Already in delay-slot.");
- _delay_state = AtDelay;
-#endif
- }
-
- inline void induce_pc_hazard() {
-#ifdef VALIDATE_PIPELINE
- assert_no_hazard();
- _hazard_state = PcHazard;
-#endif
- }
-
- bool is_cbcond_before() { return offset() > 0 ? is_cbcond(prev_insn()) : false; }
-
- bool is_rdpc_before() { return offset() > 0 ? is_rdpc(prev_insn()) : false; }
-
- void assert_no_cbcond_before() {
- assert(offset() == 0 || !is_cbcond_before(), "CBCOND should not be followed by CTI.");
- }
-
- void assert_no_rdpc_before() {
- assert(offset() == 0 || !is_rdpc_before(), "RDPC should not be followed by CTI.");
- }
-
- public:
-
- bool use_cbcond(Label &L) {
- if (!UseCBCond || is_cbcond_before()) return false;
- intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc());
- assert((x & 3) == 0, "not word aligned");
- return is_simm12(x);
- }
-
- // Tells assembler you know that next instruction is delayed
- Assembler* delayed() {
-#ifdef VALIDATE_PIPELINE
- assert(_delay_state == AtDelay, "Delayed instruction not in delay-slot.");
- _delay_state = FillDelay;
-#endif
- return this;
- }
-
- void flush() {
-#ifdef VALIDATE_PIPELINE
- assert(_delay_state == NoDelay, "Ending code with a delay-slot.");
-#ifdef COMPILER2
- validate_no_pipeline_hazards();
-#endif
-#endif
- AbstractAssembler::flush();
- }
-
- inline void emit_int32(int32_t); // shadows AbstractAssembler::emit_int32
- inline void emit_data(int32_t);
- inline void emit_data(int32_t, RelocationHolder const&);
- inline void emit_data(int32_t, relocInfo::relocType rtype);
-
- // Helper for the above functions.
- inline void check_delay();
-
-
- public:
- // instructions, refer to page numbers in the SPARC Architecture Manual, V9
-
- // pp 135
-
- inline void add(Register s1, Register s2, Register d);
- inline void add(Register s1, int simm13a, Register d);
-
- inline void addcc(Register s1, Register s2, Register d);
- inline void addcc(Register s1, int simm13a, Register d);
- inline void addc(Register s1, Register s2, Register d);
- inline void addc(Register s1, int simm13a, Register d);
- inline void addccc(Register s1, Register s2, Register d);
- inline void addccc(Register s1, int simm13a, Register d);
-
-
- // 4-operand AES instructions
-
- inline void aes_eround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_eround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_dround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_dround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_eround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_eround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_dround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_dround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void aes_kexpand1(FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d);
-
-
- // 3-operand AES instructions
-
- inline void aes_kexpand0(FloatRegister s1, FloatRegister s2, FloatRegister d);
- inline void aes_kexpand2(FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- // pp 136
-
- inline void bpr(RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt = relocInfo::none);
- inline void bpr(RCondition c, bool a, Predict p, Register s1, Label &L);
-
- // compare and branch
- inline void cbcond(Condition c, CC cc, Register s1, Register s2, Label &L);
- inline void cbcond(Condition c, CC cc, Register s1, int simm5, Label &L);
-
- protected: // use MacroAssembler::br instead
-
- // pp 138
-
- inline void fb(Condition c, bool a, address d, relocInfo::relocType rt = relocInfo::none);
- inline void fb(Condition c, bool a, Label &L);
-
- // pp 141
-
- inline void fbp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none);
- inline void fbp(Condition c, bool a, CC cc, Predict p, Label &L);
-
- // pp 144
-
- inline void br(Condition c, bool a, address d, relocInfo::relocType rt = relocInfo::none);
- inline void br(Condition c, bool a, Label &L);
-
- // pp 146
-
- inline void bp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none);
- inline void bp(Condition c, bool a, CC cc, Predict p, Label &L);
-
- // pp 149
-
- inline void call(address d, relocInfo::relocType rt = relocInfo::runtime_call_type);
- inline void call(Label &L, relocInfo::relocType rt = relocInfo::runtime_call_type);
-
- inline void call(address d, RelocationHolder const &rspec);
-
- public:
-
- // pp 150
-
- // These instructions compare the contents of s2 with the contents of
- // memory at address in s1. If the values are equal, the contents of memory
- // at address s1 is swapped with the data in d. If the values are not equal,
- // the the contents of memory at s1 is loaded into d, without the swap.
-
- inline void casa(Register s1, Register s2, Register d, int ia = -1);
- inline void casxa(Register s1, Register s2, Register d, int ia = -1);
-
- // pp 152
-
- inline void udiv(Register s1, Register s2, Register d);
- inline void udiv(Register s1, int simm13a, Register d);
- inline void sdiv(Register s1, Register s2, Register d);
- inline void sdiv(Register s1, int simm13a, Register d);
- inline void udivcc(Register s1, Register s2, Register d);
- inline void udivcc(Register s1, int simm13a, Register d);
- inline void sdivcc(Register s1, Register s2, Register d);
- inline void sdivcc(Register s1, int simm13a, Register d);
-
- // pp 155
-
- inline void done();
- inline void retry();
-
- // pp 156
-
- inline void fadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d);
- inline void fsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- // pp 157
-
- inline void fcmp(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2);
- inline void fcmpe(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2);
-
- // pp 159
-
- inline void ftox(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
- inline void ftoi(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
-
- // pp 160
-
- inline void ftof(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d);
-
- // pp 161
-
- inline void fxtof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
- inline void fitof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
-
- // pp 162
-
- inline void fmov(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
-
- inline void fneg(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
-
- inline void fabs(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
-
- // pp 163
-
- inline void fmul(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d);
- inline void fmul(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d);
- inline void fdiv(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- // FXORs/FXORd instructions
-
- inline void fxor(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- // pp 164
-
- inline void fsqrt(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
-
- // fmaf instructions.
-
- inline void fmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void fmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
-
- inline void fnmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
- inline void fnmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d);
-
- // pp 165
-
- inline void flush(Register s1, Register s2);
- inline void flush(Register s1, int simm13a);
-
- // pp 167
-
- void flushw();
-
- // pp 168
-
- void illtrap(int const22a);
-
- // pp 169
-
- void impdep1(int id1, int const19a);
- void impdep2(int id1, int const19a);
-
- // pp 170
-
- void jmpl(Register s1, Register s2, Register d);
- void jmpl(Register s1, int simm13a, Register d,
- RelocationHolder const &rspec = RelocationHolder());
-
- // 171
-
- inline void ldf(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d);
- inline void ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d,
- RelocationHolder const &rspec = RelocationHolder());
-
- inline void ldd(Register s1, Register s2, FloatRegister d);
- inline void ldd(Register s1, int simm13a, FloatRegister d);
-
- inline void ldfsr(Register s1, Register s2);
- inline void ldfsr(Register s1, int simm13a);
- inline void ldxfsr(Register s1, Register s2);
- inline void ldxfsr(Register s1, int simm13a);
-
- // 173
-
- inline void ldfa(FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d);
- inline void ldfa(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d);
-
- // pp 175
-
- inline void ldsb(Register s1, Register s2, Register d);
- inline void ldsb(Register s1, int simm13a, Register d);
- inline void ldsh(Register s1, Register s2, Register d);
- inline void ldsh(Register s1, int simm13a, Register d);
- inline void ldsw(Register s1, Register s2, Register d);
- inline void ldsw(Register s1, int simm13a, Register d);
- inline void ldub(Register s1, Register s2, Register d);
- inline void ldub(Register s1, int simm13a, Register d);
- inline void lduh(Register s1, Register s2, Register d);
- inline void lduh(Register s1, int simm13a, Register d);
- inline void lduw(Register s1, Register s2, Register d);
- inline void lduw(Register s1, int simm13a, Register d);
- inline void ldx(Register s1, Register s2, Register d);
- inline void ldx(Register s1, int simm13a, Register d);
-
- // pp 177
-
- inline void ldsba(Register s1, Register s2, int ia, Register d);
- inline void ldsba(Register s1, int simm13a, Register d);
- inline void ldsha(Register s1, Register s2, int ia, Register d);
- inline void ldsha(Register s1, int simm13a, Register d);
- inline void ldswa(Register s1, Register s2, int ia, Register d);
- inline void ldswa(Register s1, int simm13a, Register d);
- inline void lduba(Register s1, Register s2, int ia, Register d);
- inline void lduba(Register s1, int simm13a, Register d);
- inline void lduha(Register s1, Register s2, int ia, Register d);
- inline void lduha(Register s1, int simm13a, Register d);
- inline void lduwa(Register s1, Register s2, int ia, Register d);
- inline void lduwa(Register s1, int simm13a, Register d);
- inline void ldxa(Register s1, Register s2, int ia, Register d);
- inline void ldxa(Register s1, int simm13a, Register d);
-
- // pp 181
-
- inline void and3(Register s1, Register s2, Register d);
- inline void and3(Register s1, int simm13a, Register d);
- inline void andcc(Register s1, Register s2, Register d);
- inline void andcc(Register s1, int simm13a, Register d);
- inline void andn(Register s1, Register s2, Register d);
- inline void andn(Register s1, int simm13a, Register d);
- inline void andncc(Register s1, Register s2, Register d);
- inline void andncc(Register s1, int simm13a, Register d);
- inline void or3(Register s1, Register s2, Register d);
- inline void or3(Register s1, int simm13a, Register d);
- inline void orcc(Register s1, Register s2, Register d);
- inline void orcc(Register s1, int simm13a, Register d);
- inline void orn(Register s1, Register s2, Register d);
- inline void orn(Register s1, int simm13a, Register d);
- inline void orncc(Register s1, Register s2, Register d);
- inline void orncc(Register s1, int simm13a, Register d);
- inline void xor3(Register s1, Register s2, Register d);
- inline void xor3(Register s1, int simm13a, Register d);
- inline void xorcc(Register s1, Register s2, Register d);
- inline void xorcc(Register s1, int simm13a, Register d);
- inline void xnor(Register s1, Register s2, Register d);
- inline void xnor(Register s1, int simm13a, Register d);
- inline void xnorcc(Register s1, Register s2, Register d);
- inline void xnorcc(Register s1, int simm13a, Register d);
-
- // pp 183
-
- inline void membar(Membar_mask_bits const7a);
-
- // pp 185
-
- inline void fmov(FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d);
-
- // pp 189
-
- inline void fmov(FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d);
-
- // pp 191
-
- inline void movcc(Condition c, bool floatCC, CC cca, Register s2, Register d);
- inline void movcc(Condition c, bool floatCC, CC cca, int simm11a, Register d);
-
- // pp 195
-
- inline void movr(RCondition c, Register s1, Register s2, Register d);
- inline void movr(RCondition c, Register s1, int simm10a, Register d);
-
- // pp 196
-
- inline void mulx(Register s1, Register s2, Register d);
- inline void mulx(Register s1, int simm13a, Register d);
- inline void sdivx(Register s1, Register s2, Register d);
- inline void sdivx(Register s1, int simm13a, Register d);
- inline void udivx(Register s1, Register s2, Register d);
- inline void udivx(Register s1, int simm13a, Register d);
-
- // pp 197
-
- inline void umul(Register s1, Register s2, Register d);
- inline void umul(Register s1, int simm13a, Register d);
- inline void smul(Register s1, Register s2, Register d);
- inline void smul(Register s1, int simm13a, Register d);
- inline void umulcc(Register s1, Register s2, Register d);
- inline void umulcc(Register s1, int simm13a, Register d);
- inline void smulcc(Register s1, Register s2, Register d);
- inline void smulcc(Register s1, int simm13a, Register d);
-
- // pp 201
-
- inline void nop();
-
- inline void sw_count();
-
- // pp 202
-
- inline void popc(Register s, Register d);
- inline void popc(int simm13a, Register d);
-
- // pp 203
-
- inline void prefetch(Register s1, Register s2, PrefetchFcn f);
- inline void prefetch(Register s1, int simm13a, PrefetchFcn f);
-
- inline void prefetcha(Register s1, Register s2, int ia, PrefetchFcn f);
- inline void prefetcha(Register s1, int simm13a, PrefetchFcn f);
-
- // pp 208
-
- // not implementing read privileged register
-
- inline void rdy(Register d);
- inline void rdccr(Register d);
- inline void rdasi(Register d);
- inline void rdtick(Register d);
- inline void rdpc(Register d);
- inline void rdfprs(Register d);
-
- // pp 213
-
- inline void rett(Register s1, Register s2);
- inline void rett(Register s1, int simm13a, relocInfo::relocType rt = relocInfo::none);
-
- // pp 214
-
- inline void save(Register s1, Register s2, Register d);
- inline void save(Register s1, int simm13a, Register d);
-
- inline void restore(Register s1 = G0, Register s2 = G0, Register d = G0);
- inline void restore(Register s1, int simm13a, Register d);
-
- // pp 216
-
- inline void saved();
- inline void restored();
-
- // pp 217
-
- inline void sethi(int imm22a, Register d, RelocationHolder const &rspec = RelocationHolder());
-
- // pp 218
-
- inline void sll(Register s1, Register s2, Register d);
- inline void sll(Register s1, int imm5a, Register d);
- inline void srl(Register s1, Register s2, Register d);
- inline void srl(Register s1, int imm5a, Register d);
- inline void sra(Register s1, Register s2, Register d);
- inline void sra(Register s1, int imm5a, Register d);
-
- inline void sllx(Register s1, Register s2, Register d);
- inline void sllx(Register s1, int imm6a, Register d);
- inline void srlx(Register s1, Register s2, Register d);
- inline void srlx(Register s1, int imm6a, Register d);
- inline void srax(Register s1, Register s2, Register d);
- inline void srax(Register s1, int imm6a, Register d);
-
- // pp 220
-
- inline void sir(int simm13a);
-
- // pp 221
-
- inline void stbar();
-
- // pp 222
-
- inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2);
- inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a);
-
- inline void std(FloatRegister d, Register s1, Register s2);
- inline void std(FloatRegister d, Register s1, int simm13a);
-
- inline void stfsr(Register s1, Register s2);
- inline void stfsr(Register s1, int simm13a);
- inline void stxfsr(Register s1, Register s2);
- inline void stxfsr(Register s1, int simm13a);
-
- // pp 224
-
- inline void stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia);
- inline void stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a);
-
- // pp 226
-
- inline void stb(Register d, Register s1, Register s2);
- inline void stb(Register d, Register s1, int simm13a);
- inline void sth(Register d, Register s1, Register s2);
- inline void sth(Register d, Register s1, int simm13a);
- inline void stw(Register d, Register s1, Register s2);
- inline void stw(Register d, Register s1, int simm13a);
- inline void stx(Register d, Register s1, Register s2);
- inline void stx(Register d, Register s1, int simm13a);
-
- // pp 177
-
- inline void stba(Register d, Register s1, Register s2, int ia);
- inline void stba(Register d, Register s1, int simm13a);
- inline void stha(Register d, Register s1, Register s2, int ia);
- inline void stha(Register d, Register s1, int simm13a);
- inline void stwa(Register d, Register s1, Register s2, int ia);
- inline void stwa(Register d, Register s1, int simm13a);
- inline void stxa(Register d, Register s1, Register s2, int ia);
- inline void stxa(Register d, Register s1, int simm13a);
- inline void stda(Register d, Register s1, Register s2, int ia);
- inline void stda(Register d, Register s1, int simm13a);
-
- // pp 230
-
- inline void sub(Register s1, Register s2, Register d);
- inline void sub(Register s1, int simm13a, Register d);
-
- inline void subcc(Register s1, Register s2, Register d);
- inline void subcc(Register s1, int simm13a, Register d);
- inline void subc(Register s1, Register s2, Register d);
- inline void subc(Register s1, int simm13a, Register d);
- inline void subccc(Register s1, Register s2, Register d);
- inline void subccc(Register s1, int simm13a, Register d);
-
- // pp 231
-
- inline void swap(Register s1, Register s2, Register d);
- inline void swap(Register s1, int simm13a, Register d);
-
- // pp 232
-
- inline void swapa(Register s1, Register s2, int ia, Register d);
- inline void swapa(Register s1, int simm13a, Register d);
-
- // pp 234, note op in book is wrong, see pp 268
-
- inline void taddcc(Register s1, Register s2, Register d);
- inline void taddcc(Register s1, int simm13a, Register d);
-
- // pp 235
-
- inline void tsubcc(Register s1, Register s2, Register d);
- inline void tsubcc(Register s1, int simm13a, Register d);
-
- // pp 237
-
- inline void trap(Condition c, CC cc, Register s1, Register s2);
- inline void trap(Condition c, CC cc, Register s1, int trapa);
- // simple uncond. trap
- inline void trap(int trapa);
-
- // pp 239 omit write priv register for now
-
- inline void wry(Register d);
- inline void wrccr(Register s);
- inline void wrccr(Register s, int simm13a);
- inline void wrasi(Register d);
- // wrasi(d, imm) stores (d xor imm) to asi
- inline void wrasi(Register d, int simm13a);
- inline void wrfprs(Register d);
-
- // VIS1 instructions
-
- inline void alignaddr(Register s1, Register s2, Register d);
-
- inline void faligndata(FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- inline void fzero(FloatRegisterImpl::Width w, FloatRegister d);
-
- inline void fsrc2(FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d);
-
- inline void fnot1(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d);
-
- inline void fpmerge(FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- inline void stpartialf(Register s1, Register s2, FloatRegister d, int ia = -1);
-
- // VIS2 instructions
-
- inline void edge8n(Register s1, Register s2, Register d);
-
- inline void bmask(Register s1, Register s2, Register d);
- inline void bshuffle(FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- // VIS3 instructions
-
- inline void addxc(Register s1, Register s2, Register d);
- inline void addxccc(Register s1, Register s2, Register d);
-
- inline void movstosw(FloatRegister s, Register d);
- inline void movstouw(FloatRegister s, Register d);
- inline void movdtox(FloatRegister s, Register d);
-
- inline void movwtos(Register s, FloatRegister d);
- inline void movxtod(Register s, FloatRegister d);
-
- inline void xmulx(Register s1, Register s2, Register d);
- inline void xmulxhi(Register s1, Register s2, Register d);
- inline void umulxhi(Register s1, Register s2, Register d);
-
- // Crypto SHA instructions
-
- inline void sha1();
- inline void sha256();
- inline void sha512();
-
- // CRC32C instruction
-
- inline void crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d);
-
- // MPMUL instruction
-
- inline void mpmul(int uimm5);
-
- // Creation
- Assembler(CodeBuffer* code) : AbstractAssembler(code) {
-#ifdef VALIDATE_PIPELINE
- _delay_state = NoDelay;
- _hazard_state = NoHazard;
-#endif
- }
-};
-
-#endif // CPU_SPARC_ASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp b/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp
deleted file mode 100644
index df39dd9beac..00000000000
--- a/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp
+++ /dev/null
@@ -1,1130 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_ASSEMBLER_SPARC_INLINE_HPP
-#define CPU_SPARC_ASSEMBLER_SPARC_INLINE_HPP
-
-#include "asm/assembler.hpp"
-
-
-inline void Assembler::avoid_pipeline_stall() {
-#ifdef VALIDATE_PIPELINE
- if (_hazard_state == PcHazard) {
- assert(is_cbcond_before() || is_rdpc_before(), "PC-hazard not preceeded by CBCOND or RDPC.");
- assert_no_delay("Must not have PC-hazard state in delay-slot.");
- nop();
- _hazard_state = NoHazard;
- }
-#endif
-
- bool post_cond = is_cbcond_before();
- bool post_rdpc = is_rdpc_before();
-
- if (post_cond || post_rdpc) {
- nop();
-#ifdef VALIDATE_PIPELINE
- if (_hazard_state != PcHazard) {
- assert(post_cond, "CBCOND before when no hazard @0x%p\n", pc());
- assert(post_rdpc, "RDPC before when no hazard @0x%p\n", pc());
- }
-#endif
- }
-}
-
-inline void Assembler::check_delay() {
-#ifdef VALIDATE_PIPELINE
- guarantee(_delay_state != AtDelay, "Use delayed() when filling delay-slot");
- _delay_state = NoDelay;
-#endif
-}
-
-inline void Assembler::emit_int32(int32_t x) {
- check_delay();
-#ifdef VALIDATE_PIPELINE
- _hazard_state = NoHazard;
-#endif
- AbstractAssembler::emit_int32(x);
-}
-
-inline void Assembler::emit_data(int32_t x) {
- emit_int32(x);
-}
-
-inline void Assembler::emit_data(int32_t x, relocInfo::relocType rtype) {
- relocate(rtype);
- emit_int32(x);
-}
-
-inline void Assembler::emit_data(int32_t x, RelocationHolder const &rspec) {
- relocate(rspec);
- emit_int32(x);
-}
-
-
-inline void Assembler::add(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::add(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::addcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::addcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::addc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(addc_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::addc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(addc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::addccc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::addccc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::aes_eround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_eround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_dround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_dround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_eround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_l_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_eround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_l_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_dround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_l_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_dround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_l_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_kexpand1(FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | u_field(imm5a, 13, 9) | op5(aes_kexpand1_op5) | fs2(s2, FloatRegisterImpl::D));
-}
-
-// 3-operand AES instructions
-
-inline void Assembler::aes_kexpand0(FloatRegister s1, FloatRegister s2, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand0_opf) | fs2(s2, FloatRegisterImpl::D));
-}
-inline void Assembler::aes_kexpand2(FloatRegister s1, FloatRegister s2, FloatRegister d) {
- aes_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand2_opf) | fs2(s2, FloatRegisterImpl::D));
-}
-
-inline void Assembler::bpr(RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(branch_op) | annul(a) | cond(c) | op2(bpr_op2) | wdisp16(intptr_t(d), intptr_t(pc())) | predict(p) | rs1(s1), rt);
- induce_delay_slot();
-}
-inline void Assembler::bpr(RCondition c, bool a, Predict p, Register s1, Label &L) {
- // Note[+]: All assembly emit routines using the 'target()' branch back-patch
- // resolver must call 'avoid_pipeline_stall()' prior to calling 'target()'
- // (we must do so even though the call will be made, as here, in the above
- // implementation of 'bpr()', invoked below). The reason is the assumption
- // made in 'target()', where using the current PC as the address for back-
- // patching prevents any additional code to be emitted _after_ the address
- // has been set (implicitly) in order to refer to the correct instruction.
- avoid_pipeline_stall();
- bpr(c, a, p, s1, target(L));
-}
-
-inline void Assembler::fb(Condition c, bool a, address d, relocInfo::relocType rt) {
- v9_dep();
- avoid_pipeline_stall();
- cti();
- emit_data(op(branch_op) | annul(a) | cond(c) | op2(fb_op2) | wdisp(intptr_t(d), intptr_t(pc()), 22), rt);
- induce_delay_slot();
-}
-inline void Assembler::fb(Condition c, bool a, Label &L) {
- avoid_pipeline_stall();
- fb(c, a, target(L));
-}
-
-inline void Assembler::fbp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(branch_op) | annul(a) | cond(c) | op2(fbp_op2) | branchcc(cc) | predict(p) | wdisp(intptr_t(d), intptr_t(pc()), 19), rt);
- induce_delay_slot();
-}
-inline void Assembler::fbp(Condition c, bool a, CC cc, Predict p, Label &L) {
- avoid_pipeline_stall();
- fbp(c, a, cc, p, target(L));
-}
-
-inline void Assembler::br(Condition c, bool a, address d, relocInfo::relocType rt) {
- v9_dep();
- avoid_pipeline_stall();
- cti();
- emit_data(op(branch_op) | annul(a) | cond(c) | op2(br_op2) | wdisp(intptr_t(d), intptr_t(pc()), 22), rt);
- induce_delay_slot();
-}
-inline void Assembler::br(Condition c, bool a, Label &L) {
- avoid_pipeline_stall();
- br(c, a, target(L));
-}
-
-inline void Assembler::bp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(branch_op) | annul(a) | cond(c) | op2(bp_op2) | branchcc(cc) | predict(p) | wdisp(intptr_t(d), intptr_t(pc()), 19), rt);
- induce_delay_slot();
-}
-inline void Assembler::bp(Condition c, bool a, CC cc, Predict p, Label &L) {
- avoid_pipeline_stall();
- bp(c, a, cc, p, target(L));
-}
-
-// compare and branch
-inline void Assembler::cbcond(Condition c, CC cc, Register s1, Register s2, Label &L) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(branch_op) | cond_cbcond(c) | op2(bpr_op2) | branchcc(cc) | wdisp10(intptr_t(target(L)), intptr_t(pc())) | rs1(s1) | rs2(s2));
- induce_pc_hazard();
-}
-inline void Assembler::cbcond(Condition c, CC cc, Register s1, int simm5, Label &L) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(branch_op) | cond_cbcond(c) | op2(bpr_op2) | branchcc(cc) | wdisp10(intptr_t(target(L)), intptr_t(pc())) | rs1(s1) | immed(true) | simm(simm5, 5));
- induce_pc_hazard();
-}
-
-inline void Assembler::call(address d, relocInfo::relocType rt) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rt);
- induce_delay_slot();
- assert(rt != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec");
-}
-inline void Assembler::call(Label &L, relocInfo::relocType rt) {
- avoid_pipeline_stall();
- call(target(L), rt);
-}
-
-inline void Assembler::call(address d, RelocationHolder const &rspec) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rspec);
- induce_delay_slot();
- assert(rspec.type() != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec");
-}
-
-inline void Assembler::casa(Register s1, Register s2, Register d, int ia) {
- emit_int32(op(ldst_op) | rd(d) | op3(casa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2));
-}
-inline void Assembler::casxa(Register s1, Register s2, Register d, int ia) {
- emit_int32(op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2));
-}
-
-inline void Assembler::udiv(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(udiv_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::udiv(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(udiv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::sdiv(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::sdiv(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::udivcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::udivcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::sdivcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::sdivcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::done() {
- cti();
- emit_int32(op(arith_op) | fcn(0) | op3(done_op3));
-}
-inline void Assembler::retry() {
- cti();
- emit_int32(op(arith_op) | fcn(1) | op3(retry_op3));
-}
-
-inline void Assembler::fadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w));
-}
-inline void Assembler::fsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w));
-}
-
-inline void Assembler::fcmp(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) {
- emit_int32(op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w));
-}
-inline void Assembler::fcmpe(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) {
- emit_int32(op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w));
-}
-
-inline void Assembler::ftox(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w));
-}
-inline void Assembler::ftoi(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w));
-}
-
-inline void Assembler::ftof(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw));
-}
-
-inline void Assembler::fxtof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D));
-}
-inline void Assembler::fitof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S));
-}
-
-inline void Assembler::fmov(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w));
-}
-inline void Assembler::fneg(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w));
-}
-inline void Assembler::fabs(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w));
-}
-inline void Assembler::fmul(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w));
-}
-inline void Assembler::fmul(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw));
-}
-inline void Assembler::fdiv(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w));
-}
-
-inline void Assembler::fxor(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) {
- vis1_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(flog3_op3) | fs1(s1, w) | opf(0x6E - w) | fs2(s2, w));
-}
-
-inline void Assembler::fsqrt(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w));
-}
-
-inline void Assembler::fmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- fmaf_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(w) | fs2(s2, w));
-}
-inline void Assembler::fmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- fmaf_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0x4 + w) | fs2(s2, w));
-}
-
-inline void Assembler::fnmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- fmaf_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0xc + w) | fs2(s2, w));
-}
-inline void Assembler::fnmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) {
- fmaf_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0x8 + w) | fs2(s2, w));
-}
-
-inline void Assembler::flush(Register s1, Register s2) {
- emit_int32(op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::flush(Register s1, int simm13a) {
- emit_data(op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::flushw() {
- emit_int32(op(arith_op) | op3(flushw_op3));
-}
-
-inline void Assembler::illtrap(int const22a) {
- emit_int32(op(branch_op) | u_field(const22a, 21, 0));
-}
-
-inline void Assembler::impdep1(int id1, int const19a) {
- emit_int32(op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0));
-}
-inline void Assembler::impdep2(int id1, int const19a) {
- emit_int32(op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0));
-}
-
-inline void Assembler::jmpl(Register s1, Register s2, Register d) {
- avoid_pipeline_stall();
- cti();
- emit_int32(op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | rs2(s2));
- induce_delay_slot();
-}
-inline void Assembler::jmpl(Register s1, int simm13a, Register d, RelocationHolder const &rspec) {
- avoid_pipeline_stall();
- cti();
- emit_data(op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec);
- induce_delay_slot();
-}
-
-inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) {
- emit_int32(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, RelocationHolder const &rspec) {
- emit_data(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec);
-}
-
-inline void Assembler::ldd(Register s1, Register s2, FloatRegister d) {
- assert(d->is_even(), "not even");
- ldf(FloatRegisterImpl::D, s1, s2, d);
-}
-inline void Assembler::ldd(Register s1, int simm13a, FloatRegister d) {
- assert(d->is_even(), "not even");
- ldf(FloatRegisterImpl::D, s1, simm13a, d);
-}
-
-inline void Assembler::ldxfsr(Register s1, Register s2) {
- emit_int32(op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::ldxfsr(Register s1, int simm13a) {
- emit_data(op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::ldfa(FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d) {
- emit_int32(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::ldfa(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d) {
- emit_int32(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::ldsb(Register s1, Register s2, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::ldsb(Register s1, int simm13a, Register d) {
- emit_data(op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::ldsh(Register s1, Register s2, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsh_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::ldsh(Register s1, int simm13a, Register d) {
- emit_data(op(ldst_op) | rd(d) | op3(ldsh_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::ldsw(Register s1, Register s2, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsw_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::ldsw(Register s1, int simm13a, Register d) {
- emit_data(op(ldst_op) | rd(d) | op3(ldsw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::ldub(Register s1, Register s2, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::ldub(Register s1, int simm13a, Register d) {
- emit_data(op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::lduh(Register s1, Register s2, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(lduh_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::lduh(Register s1, int simm13a, Register d) {
- emit_data(op(ldst_op) | rd(d) | op3(lduh_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::lduw(Register s1, Register s2, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(lduw_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::lduw(Register s1, int simm13a, Register d) {
- emit_data(op(ldst_op) | rd(d) | op3(lduw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::ldx(Register s1, Register s2, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::ldx(Register s1, int simm13a, Register d) {
- emit_data(op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::ldsba(Register s1, Register s2, int ia, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::ldsba(Register s1, int simm13a, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::ldsha(Register s1, Register s2, int ia, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::ldsha(Register s1, int simm13a, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::ldswa(Register s1, Register s2, int ia, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::ldswa(Register s1, int simm13a, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::lduba(Register s1, Register s2, int ia, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::lduba(Register s1, int simm13a, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::lduha(Register s1, Register s2, int ia, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::lduha(Register s1, int simm13a, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::lduwa(Register s1, Register s2, int ia, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::lduwa(Register s1, int simm13a, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::ldxa(Register s1, Register s2, int ia, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::ldxa(Register s1, int simm13a, Register d) {
- emit_int32(op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::and3(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(and_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::and3(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(and_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::andcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::andcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::andn(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(andn_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::andn(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(andn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::andncc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::andncc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::or3(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(or_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::or3(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(or_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::orcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::orcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::orn(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::orn(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::orncc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::orncc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::xor3(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xor_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::xor3(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xor_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::xorcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::xorcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::xnor(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xnor_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::xnor(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xnor_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::xnorcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::xnorcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::membar(Membar_mask_bits const7a) {
- emit_int32(op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field(int(const7a), 6, 0));
-}
-
-inline void Assembler::fmov(FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w));
-}
-
-inline void Assembler::fmov(FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d) {
- emit_int32(op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w));
-}
-
-inline void Assembler::movcc(Condition c, bool floatCC, CC cca, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2));
-}
-inline void Assembler::movcc(Condition c, bool floatCC, CC cca, int simm11a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11));
-}
-
-inline void Assembler::movr(RCondition c, Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2));
-}
-inline void Assembler::movr(RCondition c, Register s1, int simm10a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10));
-}
-
-inline void Assembler::mulx(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(mulx_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::mulx(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(mulx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::sdivx(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::sdivx(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::udivx(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::udivx(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::umul(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(umul_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::umul(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(umul_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::smul(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(smul_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::smul(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(smul_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::umulcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::umulcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::smulcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::smulcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::nop() {
- emit_int32(op(branch_op) | op2(sethi_op2));
-}
-
-inline void Assembler::sw_count() {
- emit_int32(op(branch_op) | op2(sethi_op2) | 0x3f0);
-}
-
-inline void Assembler::popc(Register s, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(popc_op3) | rs2(s));
-}
-inline void Assembler::popc(int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::prefetch(Register s1, Register s2, PrefetchFcn f) {
- emit_int32(op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::prefetch(Register s1, int simm13a, PrefetchFcn f) {
- emit_data(op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::prefetcha(Register s1, Register s2, int ia, PrefetchFcn f) {
- emit_int32(op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::prefetcha(Register s1, int simm13a, PrefetchFcn f) {
- emit_int32(op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::rdy(Register d) {
- v9_dep();
- emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14));
-}
-inline void Assembler::rdccr(Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14));
-}
-inline void Assembler::rdasi(Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14));
-}
-inline void Assembler::rdtick(Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14));
-}
-inline void Assembler::rdpc(Register d) {
- avoid_pipeline_stall();
- cti();
- emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14));
- induce_pc_hazard();
-}
-inline void Assembler::rdfprs(Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14));
-}
-
-inline void Assembler::rett(Register s1, Register s2) {
- cti();
- emit_int32(op(arith_op) | op3(rett_op3) | rs1(s1) | rs2(s2));
- induce_delay_slot();
-}
-inline void Assembler::rett(Register s1, int simm13a, relocInfo::relocType rt) {
- cti();
- emit_data(op(arith_op) | op3(rett_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rt);
- induce_delay_slot();
-}
-
-inline void Assembler::save(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::save(Register s1, int simm13a, Register d) {
- // make sure frame is at least large enough for the register save area
- assert(-simm13a >= 16 * wordSize, "frame too small");
- emit_int32(op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::restore(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::restore(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-// pp 216
-
-inline void Assembler::saved() {
- emit_int32(op(arith_op) | fcn(0) | op3(saved_op3));
-}
-inline void Assembler::restored() {
- emit_int32(op(arith_op) | fcn(1) | op3(saved_op3));
-}
-
-inline void Assembler::sethi(int imm22a, Register d, RelocationHolder const &rspec) {
- emit_data(op(branch_op) | rd(d) | op2(sethi_op2) | hi22(imm22a), rspec);
-}
-
-inline void Assembler::sll(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2));
-}
-inline void Assembler::sll(Register s1, int imm5a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0));
-}
-inline void Assembler::srl(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2));
-}
-inline void Assembler::srl(Register s1, int imm5a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0));
-}
-inline void Assembler::sra(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2));
-}
-inline void Assembler::sra(Register s1, int imm5a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0));
-}
-
-inline void Assembler::sllx(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2));
-}
-inline void Assembler::sllx(Register s1, int imm6a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0));
-}
-inline void Assembler::srlx(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2));
-}
-inline void Assembler::srlx(Register s1, int imm6a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0));
-}
-inline void Assembler::srax(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2));
-}
-inline void Assembler::srax(Register s1, int imm6a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0));
-}
-
-inline void Assembler::sir(int simm13a) {
- emit_int32(op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13));
-}
-
-// pp 221
-
-inline void Assembler::stbar() {
- emit_int32(op(arith_op) | op3(membar_op3) | u_field(15, 18, 14));
-}
-
-// pp 222
-
-inline void Assembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2) {
- emit_int32(op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a) {
- emit_data(op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::std(FloatRegister d, Register s1, Register s2) {
- assert(d->is_even(), "not even");
- stf(FloatRegisterImpl::D, d, s1, s2);
-}
-inline void Assembler::std(FloatRegister d, Register s1, int simm13a) {
- assert(d->is_even(), "not even");
- stf(FloatRegisterImpl::D, d, s1, simm13a);
-}
-
-inline void Assembler::stxfsr(Register s1, Register s2) {
- emit_int32(op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::stxfsr(Register s1, int simm13a) {
- emit_data(op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia) {
- emit_int32(op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a) {
- emit_int32(op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-// p 226
-
-inline void Assembler::stb(Register d, Register s1, Register s2) {
- emit_int32(op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::stb(Register d, Register s1, int simm13a) {
- emit_data(op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::sth(Register d, Register s1, Register s2) {
- emit_int32(op(ldst_op) | rd(d) | op3(sth_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::sth(Register d, Register s1, int simm13a) {
- emit_data(op(ldst_op) | rd(d) | op3(sth_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::stw(Register d, Register s1, Register s2) {
- emit_int32(op(ldst_op) | rd(d) | op3(stw_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::stw(Register d, Register s1, int simm13a) {
- emit_data(op(ldst_op) | rd(d) | op3(stw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-
-inline void Assembler::stx(Register d, Register s1, Register s2) {
- emit_int32(op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::stx(Register d, Register s1, int simm13a) {
- emit_data(op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::stba(Register d, Register s1, Register s2, int ia) {
- emit_int32(op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::stba(Register d, Register s1, int simm13a) {
- emit_int32(op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::stha(Register d, Register s1, Register s2, int ia) {
- emit_int32(op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::stha(Register d, Register s1, int simm13a) {
- emit_int32(op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::stwa(Register d, Register s1, Register s2, int ia) {
- emit_int32(op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::stwa(Register d, Register s1, int simm13a) {
- emit_int32(op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::stxa(Register d, Register s1, Register s2, int ia) {
- emit_int32(op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::stxa(Register d, Register s1, int simm13a) {
- emit_int32(op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::stda(Register d, Register s1, Register s2, int ia) {
- emit_int32(op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::stda(Register d, Register s1, int simm13a) {
- emit_int32(op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-// pp 230
-
-inline void Assembler::sub(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sub_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::sub(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::subcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::subcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::subc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(subc_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::subc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(subc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::subccc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::subccc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-// pp 231
-
-inline void Assembler::swap(Register s1, Register s2, Register d) {
- v9_dep();
- emit_int32(op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::swap(Register s1, int simm13a, Register d) {
- v9_dep();
- emit_data(op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-inline void Assembler::swapa(Register s1, Register s2, int ia, Register d) {
- v9_dep();
- emit_int32(op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-inline void Assembler::swapa(Register s1, int simm13a, Register d) {
- v9_dep();
- emit_int32(op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-// pp 234, note op in book is wrong, see pp 268
-
-inline void Assembler::taddcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(taddcc_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::taddcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(taddcc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-// pp 235
-
-inline void Assembler::tsubcc(Register s1, Register s2, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(tsubcc_op3) | rs1(s1) | rs2(s2));
-}
-inline void Assembler::tsubcc(Register s1, int simm13a, Register d) {
- emit_int32(op(arith_op) | rd(d) | op3(tsubcc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13));
-}
-
-// pp 237
-
-inline void Assembler::trap(Condition c, CC cc, Register s1, Register s2) {
- emit_int32(op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2));
-}
-inline void Assembler::trap(Condition c, CC cc, Register s1, int trapa) {
- emit_int32(op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0));
-}
-// simple uncond. trap
-inline void Assembler::trap(int trapa) {
- trap(always, icc, G0, trapa);
-}
-
-inline void Assembler::wry(Register d) {
- v9_dep();
- emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25));
-}
-inline void Assembler::wrccr(Register s) {
- emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25));
-}
-inline void Assembler::wrccr(Register s, int simm13a) {
- emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::wrasi(Register d) {
- emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25));
-}
-// wrasi(d, imm) stores (d xor imm) to asi
-inline void Assembler::wrasi(Register d, int simm13a) {
- emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25) | immed(true) | simm(simm13a, 13));
-}
-inline void Assembler::wrfprs(Register d) {
- emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25));
-}
-
-inline void Assembler::alignaddr(Register s1, Register s2, Register d) {
- vis1_only();
- emit_int32(op(arith_op) | rd(d) | op3(alignaddr_op3) | rs1(s1) | opf(alignaddr_opf) | rs2(s2));
-}
-
-inline void Assembler::faligndata(FloatRegister s1, FloatRegister s2, FloatRegister d) {
- vis1_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(faligndata_op3) | fs1(s1, FloatRegisterImpl::D) | opf(faligndata_opf) | fs2(s2, FloatRegisterImpl::D));
-}
-
-inline void Assembler::fzero(FloatRegisterImpl::Width w, FloatRegister d) {
- vis1_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(fzero_op3) | opf(0x62 - w));
-}
-
-inline void Assembler::fsrc2(FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d) {
- vis1_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(fsrc_op3) | opf(0x7A - w) | fs2(s2, w));
-}
-
-inline void Assembler::fnot1(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d) {
- vis1_only();
- emit_int32(op(arith_op) | fd(d, w) | op3(fnot_op3) | fs1(s1, w) | opf(0x6C - w));
-}
-
-inline void Assembler::fpmerge(FloatRegister s1, FloatRegister s2, FloatRegister d) {
- vis1_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(0x36) | fs1(s1, FloatRegisterImpl::S) | opf(0x4b) | fs2(s2, FloatRegisterImpl::S));
-}
-
-inline void Assembler::stpartialf(Register s1, Register s2, FloatRegister d, int ia) {
- vis1_only();
- emit_int32(op(ldst_op) | fd(d, FloatRegisterImpl::D) | op3(stpartialf_op3) | rs1(s1) | imm_asi(ia) | rs2(s2));
-}
-
-// VIS2 instructions
-
-inline void Assembler::edge8n(Register s1, Register s2, Register d) {
- vis2_only();
- emit_int32(op(arith_op) | rd(d) | op3(edge_op3) | rs1(s1) | opf(edge8n_opf) | rs2(s2));
-}
-
-inline void Assembler::bmask(Register s1, Register s2, Register d) {
- vis2_only();
- emit_int32(op(arith_op) | rd(d) | op3(bmask_op3) | rs1(s1) | opf(bmask_opf) | rs2(s2));
-}
-inline void Assembler::bshuffle(FloatRegister s1, FloatRegister s2, FloatRegister d) {
- vis2_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(bshuffle_op3) | fs1(s1, FloatRegisterImpl::D) | opf(bshuffle_opf) | fs2(s2, FloatRegisterImpl::D));
-}
-
-// VIS3 instructions
-
-inline void Assembler::addxc(Register s1, Register s2, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(addx_op3) | rs1(s1) | opf(addxc_opf) | rs2(s2));
-}
-inline void Assembler::addxccc(Register s1, Register s2, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(addx_op3) | rs1(s1) | opf(addxccc_opf) | rs2(s2));
-}
-
-inline void Assembler::movstosw(FloatRegister s, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S));
-}
-inline void Assembler::movstouw(FloatRegister s, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S));
-}
-inline void Assembler::movdtox(FloatRegister s, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D));
-}
-
-inline void Assembler::movwtos(Register s, FloatRegister d) {
- vis3_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s));
-}
-inline void Assembler::movxtod(Register s, FloatRegister d) {
- vis3_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s));
-}
-
-inline void Assembler::xmulx(Register s1, Register s2, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulx_opf) | rs2(s2));
-}
-inline void Assembler::xmulxhi(Register s1, Register s2, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2));
-}
-inline void Assembler::umulxhi(Register s1, Register s2, Register d) {
- vis3_only();
- emit_int32(op(arith_op) | rd(d) | op3(umulx_op3) | rs1(s1) | opf(umulxhi_opf) | rs2(s2));
-}
-
-// Crypto SHA instructions
-
-inline void Assembler::sha1() {
- sha1_only();
- emit_int32(op(arith_op) | op3(sha_op3) | opf(sha1_opf));
-}
-inline void Assembler::sha256() {
- sha256_only();
- emit_int32(op(arith_op) | op3(sha_op3) | opf(sha256_opf));
-}
-inline void Assembler::sha512() {
- sha512_only();
- emit_int32(op(arith_op) | op3(sha_op3) | opf(sha512_opf));
-}
-
-// CRC32C instruction
-
-inline void Assembler::crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d) {
- crc32c_only();
- emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D));
-}
-
-// MPMUL instruction
-
-inline void Assembler::mpmul(int uimm5) {
- mpmul_only();
- emit_int32(op(arith_op) | rd(0) | op3(mpmul_op3) | rs1(0) | opf(mpmul_opf) | uimm(uimm5, 5));
-}
-
-#endif // CPU_SPARC_ASSEMBLER_SPARC_INLINE_HPP
diff --git a/src/hotspot/cpu/sparc/bytes_sparc.hpp b/src/hotspot/cpu/sparc/bytes_sparc.hpp
deleted file mode 100644
index 7d08f4d5249..00000000000
--- a/src/hotspot/cpu/sparc/bytes_sparc.hpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_BYTES_SPARC_HPP
-#define CPU_SPARC_BYTES_SPARC_HPP
-
-#include "memory/allocation.hpp"
-
-class Bytes: AllStatic {
- public:
- // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering
- // Sparc needs to check for alignment.
-
- // can I count on address always being a pointer to an unsigned char? Yes
-
- // Thus, a swap between native and Java ordering is always a no-op:
- static inline u2 swap_u2(u2 x) { return x; }
- static inline u4 swap_u4(u4 x) { return x; }
- static inline u8 swap_u8(u8 x) { return x; }
-
- static inline u2 get_native_u2(address p){
- return (intptr_t(p) & 1) == 0
- ? *(u2*)p
- : ( u2(p[0]) << 8 )
- | ( u2(p[1]) );
- }
-
- static inline u4 get_native_u4(address p) {
- switch (intptr_t(p) & 3) {
- case 0: return *(u4*)p;
-
- case 2: return ( u4( ((u2*)p)[0] ) << 16 )
- | ( u4( ((u2*)p)[1] ) );
-
- default: return ( u4(p[0]) << 24 )
- | ( u4(p[1]) << 16 )
- | ( u4(p[2]) << 8 )
- | u4(p[3]);
- }
- }
-
- static inline u8 get_native_u8(address p) {
- switch (intptr_t(p) & 7) {
- case 0: return *(u8*)p;
-
- case 4: return ( u8( ((u4*)p)[0] ) << 32 )
- | ( u8( ((u4*)p)[1] ) );
-
- case 2: return ( u8( ((u2*)p)[0] ) << 48 )
- | ( u8( ((u2*)p)[1] ) << 32 )
- | ( u8( ((u2*)p)[2] ) << 16 )
- | ( u8( ((u2*)p)[3] ) );
-
- default: return ( u8(p[0]) << 56 )
- | ( u8(p[1]) << 48 )
- | ( u8(p[2]) << 40 )
- | ( u8(p[3]) << 32 )
- | ( u8(p[4]) << 24 )
- | ( u8(p[5]) << 16 )
- | ( u8(p[6]) << 8 )
- | u8(p[7]);
- }
- }
-
-
-
- static inline void put_native_u2(address p, u2 x) {
- if ( (intptr_t(p) & 1) == 0 ) *(u2*)p = x;
- else {
- p[0] = x >> 8;
- p[1] = x;
- }
- }
-
- static inline void put_native_u4(address p, u4 x) {
- switch ( intptr_t(p) & 3 ) {
- case 0: *(u4*)p = x;
- break;
-
- case 2: ((u2*)p)[0] = x >> 16;
- ((u2*)p)[1] = x;
- break;
-
- default: ((u1*)p)[0] = x >> 24;
- ((u1*)p)[1] = x >> 16;
- ((u1*)p)[2] = x >> 8;
- ((u1*)p)[3] = x;
- break;
- }
- }
-
- static inline void put_native_u8(address p, u8 x) {
- switch ( intptr_t(p) & 7 ) {
- case 0: *(u8*)p = x;
- break;
-
- case 4: ((u4*)p)[0] = x >> 32;
- ((u4*)p)[1] = x;
- break;
-
- case 2: ((u2*)p)[0] = x >> 48;
- ((u2*)p)[1] = x >> 32;
- ((u2*)p)[2] = x >> 16;
- ((u2*)p)[3] = x;
- break;
-
- default: ((u1*)p)[0] = x >> 56;
- ((u1*)p)[1] = x >> 48;
- ((u1*)p)[2] = x >> 40;
- ((u1*)p)[3] = x >> 32;
- ((u1*)p)[4] = x >> 24;
- ((u1*)p)[5] = x >> 16;
- ((u1*)p)[6] = x >> 8;
- ((u1*)p)[7] = x;
- }
- }
-
-
- // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering)
- // (no byte-order reversal is needed since SPARC CPUs are big-endian oriented)
- static inline u2 get_Java_u2(address p) { return get_native_u2(p); }
- static inline u4 get_Java_u4(address p) { return get_native_u4(p); }
- static inline u8 get_Java_u8(address p) { return get_native_u8(p); }
-
- static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); }
- static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); }
- static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); }
-};
-
-//Reconciliation History
-// 1.7 98/02/24 10:18:41 bytes_i486.hpp
-// 1.10 98/04/08 18:47:57 bytes_i486.hpp
-// 1.13 98/07/15 17:10:03 bytes_i486.hpp
-// 1.14 98/08/13 10:38:23 bytes_i486.hpp
-// 1.15 98/10/05 16:30:21 bytes_i486.hpp
-// 1.17 99/06/22 16:37:35 bytes_i486.hpp
-//End
-
-#endif // CPU_SPARC_BYTES_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp b/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp
deleted file mode 100644
index 6f9624c054c..00000000000
--- a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "c1/c1_CodeStubs.hpp"
-#include "c1/c1_FrameMap.hpp"
-#include "c1/c1_LIRAssembler.hpp"
-#include "c1/c1_MacroAssembler.hpp"
-#include "c1/c1_Runtime1.hpp"
-#include "nativeInst_sparc.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "utilities/macros.hpp"
-#include "vmreg_sparc.inline.hpp"
-
-#define __ ce->masm()->
-
-RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array)
- : _throw_index_out_of_bounds_exception(false), _index(index), _array(array) {
- assert(info != NULL, "must have info");
- _info = new CodeEmitInfo(info);
-}
-
-RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index)
- : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) {
- assert(info != NULL, "must have info");
- _info = new CodeEmitInfo(info);
-}
-
-void RangeCheckStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
-
- if (_info->deoptimize_on_exception()) {
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
- __ call(a, relocInfo::runtime_call_type);
- __ delayed()->nop();
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
- debug_only(__ should_not_reach_here());
- return;
- }
-
- if (_index->is_register()) {
- __ mov(_index->as_register(), G4);
- } else {
- __ set(_index->as_jint(), G4);
- }
- if (_throw_index_out_of_bounds_exception) {
- __ call(Runtime1::entry_for(Runtime1::throw_index_exception_id), relocInfo::runtime_call_type);
- } else {
- __ mov(_array->as_pointer_register(), G5);
- __ call(Runtime1::entry_for(Runtime1::throw_range_check_failed_id), relocInfo::runtime_call_type);
- }
- __ delayed()->nop();
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
- debug_only(__ should_not_reach_here());
-}
-
-PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
- _info = new CodeEmitInfo(info);
-}
-
-void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
- address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
- __ call(a, relocInfo::runtime_call_type);
- __ delayed()->nop();
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
- debug_only(__ should_not_reach_here());
-}
-
-void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
- __ set(_bci, G4);
- Metadata *m = _method->as_constant_ptr()->as_metadata();
- __ set_metadata_constant(m, G5);
- __ call(Runtime1::entry_for(Runtime1::counter_overflow_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
-
- __ br(Assembler::always, true, Assembler::pt, _continuation);
- __ delayed()->nop();
-}
-
-
-void DivByZeroStub::emit_code(LIR_Assembler* ce) {
- if (_offset != -1) {
- ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
- }
- __ bind(_entry);
- __ call(Runtime1::entry_for(Runtime1::throw_div0_exception_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
-#ifdef ASSERT
- __ should_not_reach_here();
-#endif
-}
-
-
-void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
- address a;
- if (_info->deoptimize_on_exception()) {
- // Deoptimize, do not throw the exception, because it is probably wrong to do it here.
- a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
- } else {
- a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
- }
-
- ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
- __ bind(_entry);
- __ call(a, relocInfo::runtime_call_type);
- __ delayed()->nop();
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
-#ifdef ASSERT
- __ should_not_reach_here();
-#endif
-}
-
-
-// Implementation of SimpleExceptionStub
-// Note: %g1 and %g3 are already in use
-void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
- __ call(Runtime1::entry_for(_stub), relocInfo::runtime_call_type);
-
- if (_obj->is_valid()) {
- __ delayed()->mov(_obj->as_register(), G4); // _obj contains the optional argument to the stub
- } else {
- __ delayed()->mov(G0, G4);
- }
- ce->add_call_info_here(_info);
-#ifdef ASSERT
- __ should_not_reach_here();
-#endif
-}
-
-
-// Implementation of NewInstanceStub
-
-NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
- _result = result;
- _klass = klass;
- _klass_reg = klass_reg;
- _info = new CodeEmitInfo(info);
- assert(stub_id == Runtime1::new_instance_id ||
- stub_id == Runtime1::fast_new_instance_id ||
- stub_id == Runtime1::fast_new_instance_init_check_id,
- "need new_instance id");
- _stub_id = stub_id;
-}
-
-
-void NewInstanceStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
- __ call(Runtime1::entry_for(_stub_id), relocInfo::runtime_call_type);
- __ delayed()->mov_or_nop(_klass_reg->as_register(), G5);
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
- __ br(Assembler::always, false, Assembler::pt, _continuation);
- __ delayed()->mov_or_nop(O0, _result->as_register());
-}
-
-
-// Implementation of NewTypeArrayStub
-NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
- _klass_reg = klass_reg;
- _length = length;
- _result = result;
- _info = new CodeEmitInfo(info);
-}
-
-
-void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
-
- __ mov(_length->as_register(), G4);
- __ call(Runtime1::entry_for(Runtime1::new_type_array_id), relocInfo::runtime_call_type);
- __ delayed()->mov_or_nop(_klass_reg->as_register(), G5);
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
- __ br(Assembler::always, false, Assembler::pt, _continuation);
- __ delayed()->mov_or_nop(O0, _result->as_register());
-}
-
-
-// Implementation of NewObjectArrayStub
-
-NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
- _klass_reg = klass_reg;
- _length = length;
- _result = result;
- _info = new CodeEmitInfo(info);
-}
-
-
-void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
-
- __ mov(_length->as_register(), G4);
- __ call(Runtime1::entry_for(Runtime1::new_object_array_id), relocInfo::runtime_call_type);
- __ delayed()->mov_or_nop(_klass_reg->as_register(), G5);
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
- __ br(Assembler::always, false, Assembler::pt, _continuation);
- __ delayed()->mov_or_nop(O0, _result->as_register());
-}
-
-
-// Implementation of MonitorAccessStubs
-MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info)
- : MonitorAccessStub(obj_reg, lock_reg) {
- _info = new CodeEmitInfo(info);
-}
-
-
-void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
- __ mov(_obj_reg->as_register(), G4);
- if (ce->compilation()->has_fpu_code()) {
- __ call(Runtime1::entry_for(Runtime1::monitorenter_id), relocInfo::runtime_call_type);
- } else {
- __ call(Runtime1::entry_for(Runtime1::monitorenter_nofpu_id), relocInfo::runtime_call_type);
- }
- __ delayed()->mov_or_nop(_lock_reg->as_register(), G5);
- ce->add_call_info_here(_info);
- ce->verify_oop_map(_info);
- __ br(Assembler::always, true, Assembler::pt, _continuation);
- __ delayed()->nop();
-}
-
-
-void MonitorExitStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
- if (_compute_lock) {
- ce->monitor_address(_monitor_ix, _lock_reg);
- }
- if (ce->compilation()->has_fpu_code()) {
- __ call(Runtime1::entry_for(Runtime1::monitorexit_id), relocInfo::runtime_call_type);
- } else {
- __ call(Runtime1::entry_for(Runtime1::monitorexit_nofpu_id), relocInfo::runtime_call_type);
- }
-
- __ delayed()->mov_or_nop(_lock_reg->as_register(), G4);
- __ br(Assembler::always, true, Assembler::pt, _continuation);
- __ delayed()->nop();
-}
-
-// Implementation of patching:
-// - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes)
-// - Replace original code with a call to the stub
-// At Runtime:
-// - call to stub, jump to runtime
-// - in runtime: preserve all registers (especially objects, i.e., source and destination object)
-// - in runtime: after initializing class, restore original code, reexecute instruction
-
-int PatchingStub::_patch_info_offset = -NativeGeneralJump::instruction_size;
-
-void PatchingStub::align_patch_site(MacroAssembler* ) {
- // patch sites on sparc are always properly aligned.
-}
-
-void PatchingStub::emit_code(LIR_Assembler* ce) {
- // copy original code here
- assert(NativeCall::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF,
- "not enough room for call");
- assert((_bytes_to_copy & 0x3) == 0, "must copy a multiple of four bytes");
-
- Label call_patch;
-
- int being_initialized_entry = __ offset();
-
- if (_id == load_klass_id) {
- // produce a copy of the load klass instruction for use by the being initialized case
-#ifdef ASSERT
- address start = __ pc();
-#endif
- AddressLiteral addrlit(NULL, metadata_Relocation::spec(_index));
- __ patchable_set(addrlit, _obj);
-
-#ifdef ASSERT
- for (int i = 0; i < _bytes_to_copy; i++) {
- address ptr = (address)(_pc_start + i);
- int a_byte = (*ptr) & 0xFF;
- assert(a_byte == *start++, "should be the same code");
- }
-#endif
- } else if (_id == load_mirror_id || _id == load_appendix_id) {
- // produce a copy of the load mirror instruction for use by the being initialized case
-#ifdef ASSERT
- address start = __ pc();
-#endif
- AddressLiteral addrlit(NULL, oop_Relocation::spec(_index));
- __ patchable_set(addrlit, _obj);
-
-#ifdef ASSERT
- for (int i = 0; i < _bytes_to_copy; i++) {
- address ptr = (address)(_pc_start + i);
- int a_byte = (*ptr) & 0xFF;
- assert(a_byte == *start++, "should be the same code");
- }
-#endif
- } else {
- // make a copy the code which is going to be patched.
- for (int i = 0; i < _bytes_to_copy; i++) {
- address ptr = (address)(_pc_start + i);
- int a_byte = (*ptr) & 0xFF;
- __ emit_int8 (a_byte);
- }
- }
-
- address end_of_patch = __ pc();
- int bytes_to_skip = 0;
- if (_id == load_mirror_id) {
- int offset = __ offset();
- if (CommentedAssembly) {
- __ block_comment(" being_initialized check");
- }
-
- // static field accesses have special semantics while the class
- // initializer is being run so we emit a test which can be used to
- // check that this code is being executed by the initializing
- // thread.
- assert(_obj != noreg, "must be a valid register");
- assert(_index >= 0, "must have oop index");
- __ ld_ptr(_obj, java_lang_Class::klass_offset_in_bytes(), G3);
- __ ld_ptr(G3, in_bytes(InstanceKlass::init_thread_offset()), G3);
- __ cmp_and_brx_short(G2_thread, G3, Assembler::notEqual, Assembler::pn, call_patch);
-
- // load_klass patches may execute the patched code before it's
- // copied back into place so we need to jump back into the main
- // code of the nmethod to continue execution.
- __ br(Assembler::always, false, Assembler::pt, _patch_site_continuation);
- __ delayed()->nop();
-
- // make sure this extra code gets skipped
- bytes_to_skip += __ offset() - offset;
- }
-
- // Now emit the patch record telling the runtime how to find the
- // pieces of the patch. We only need 3 bytes but it has to be
- // aligned as an instruction so emit 4 bytes.
- int sizeof_patch_record = 4;
- bytes_to_skip += sizeof_patch_record;
-
- // emit the offsets needed to find the code to patch
- int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record;
-
- // Emit the patch record. We need to emit a full word, so emit an extra empty byte
- __ emit_int8(0);
- __ emit_int8(being_initialized_entry_offset);
- __ emit_int8(bytes_to_skip);
- __ emit_int8(_bytes_to_copy);
- address patch_info_pc = __ pc();
- assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info");
-
- address entry = __ pc();
- NativeGeneralJump::insert_unconditional((address)_pc_start, entry);
- address target = NULL;
- relocInfo::relocType reloc_type = relocInfo::none;
- switch (_id) {
- case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break;
- case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break;
- case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break;
- case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break;
- default: ShouldNotReachHere();
- }
- __ bind(call_patch);
-
- if (CommentedAssembly) {
- __ block_comment("patch entry point");
- }
- __ call(target, relocInfo::runtime_call_type);
- __ delayed()->nop();
- assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change");
- ce->add_call_info_here(_info);
- __ br(Assembler::always, false, Assembler::pt, _patch_site_entry);
- __ delayed()->nop();
- if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) {
- CodeSection* cs = __ code_section();
- address pc = (address)_pc_start;
- RelocIterator iter(cs, pc, pc + 1);
- relocInfo::change_reloc_info_for_address(&iter, (address) pc, reloc_type, relocInfo::none);
-
- pc = (address)(_pc_start + NativeMovConstReg::add_offset);
- RelocIterator iter2(cs, pc, pc+1);
- relocInfo::change_reloc_info_for_address(&iter2, (address) pc, reloc_type, relocInfo::none);
- }
-
-}
-
-
-void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
- __ bind(_entry);
- __ set(_trap_request, G4);
- __ call(Runtime1::entry_for(Runtime1::deoptimize_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- ce->add_call_info_here(_info);
- DEBUG_ONLY(__ should_not_reach_here());
-}
-
-
-void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
- //---------------slow case: call to native-----------------
- __ bind(_entry);
- __ mov(src()->as_register(), O0);
- __ mov(src_pos()->as_register(), O1);
- __ mov(dst()->as_register(), O2);
- __ mov(dst_pos()->as_register(), O3);
- __ mov(length()->as_register(), O4);
-
- ce->emit_static_call_stub();
- if (ce->compilation()->bailed_out()) {
- return; // CodeCache is full
- }
-
- __ call(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type);
- __ delayed()->nop();
- ce->add_call_info_here(info());
- ce->verify_oop_map(info());
-
-#ifndef PRODUCT
- __ set((intptr_t)&Runtime1::_arraycopy_slowcase_cnt, O0);
- __ ld(O0, 0, O1);
- __ inc(O1);
- __ st(O1, 0, O0);
-#endif
-
- __ br(Assembler::always, false, Assembler::pt, _continuation);
- __ delayed()->nop();
-}
-
-#undef __
diff --git a/src/hotspot/cpu/sparc/c1_Defs_sparc.hpp b/src/hotspot/cpu/sparc/c1_Defs_sparc.hpp
deleted file mode 100644
index 2a2f75ace11..00000000000
--- a/src/hotspot/cpu/sparc/c1_Defs_sparc.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C1_DEFS_SPARC_HPP
-#define CPU_SPARC_C1_DEFS_SPARC_HPP
-
-// native word offsets from memory address (big endian)
-enum {
- pd_lo_word_offset_in_bytes = BytesPerInt,
- pd_hi_word_offset_in_bytes = 0
-};
-
-
-// explicit rounding operations are not required to implement the strictFP mode
-enum {
- pd_strict_fp_requires_explicit_rounding = false
-};
-
-
-// registers
-enum {
- pd_nof_cpu_regs_frame_map = 32, // number of registers used during code emission
- pd_nof_caller_save_cpu_regs_frame_map = 10, // number of cpu registers killed by calls
- pd_nof_cpu_regs_reg_alloc = 20, // number of registers that are visible to register allocator
- pd_nof_cpu_regs_linearscan = 32,// number of registers visible linear scan
- pd_first_cpu_reg = 0,
- pd_last_cpu_reg = 31,
- pd_last_allocatable_cpu_reg = 19,
- pd_first_callee_saved_reg = 0,
- pd_last_callee_saved_reg = 13,
-
- pd_nof_fpu_regs_frame_map = 32, // number of registers used during code emission
- pd_nof_caller_save_fpu_regs_frame_map = 32, // number of fpu registers killed by calls
- pd_nof_fpu_regs_reg_alloc = 32, // number of registers that are visible to register allocator
- pd_nof_fpu_regs_linearscan = 32, // number of registers visible to linear scan
- pd_first_fpu_reg = pd_nof_cpu_regs_frame_map,
- pd_last_fpu_reg = pd_nof_cpu_regs_frame_map + pd_nof_fpu_regs_frame_map - 1,
-
- pd_nof_xmm_regs_linearscan = 0,
- pd_nof_caller_save_xmm_regs = 0,
- pd_first_xmm_reg = -1,
- pd_last_xmm_reg = -1
-};
-
-
-// for debug info: a float value in a register is saved in single precision by runtime stubs
-enum {
- pd_float_saved_as_double = false
-};
-
-#endif // CPU_SPARC_C1_DEFS_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.cpp b/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.cpp
deleted file mode 100644
index abaf500ebd7..00000000000
--- a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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.
- *
- */
-
-// No FPU stack on SPARC
diff --git a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.hpp b/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.hpp
deleted file mode 100644
index bc0717bdc2b..00000000000
--- a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C1_FPUSTACKSIM_SPARC_HPP
-#define CPU_SPARC_C1_FPUSTACKSIM_SPARC_HPP
-
-// No FPU stack on SPARC
-class FpuStackSim;
-
-#endif // CPU_SPARC_C1_FPUSTACKSIM_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.cpp b/src/hotspot/cpu/sparc/c1_FrameMap_sparc.cpp
deleted file mode 100644
index 2e2e737d850..00000000000
--- a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.cpp
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "c1/c1_FrameMap.hpp"
-#include "c1/c1_LIR.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "vmreg_sparc.inline.hpp"
-
-
-const int FrameMap::pd_c_runtime_reserved_arg_size = 7;
-
-
-LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool outgoing) {
- LIR_Opr opr = LIR_OprFact::illegalOpr;
- VMReg r_1 = reg->first();
- VMReg r_2 = reg->second();
- if (r_1->is_stack()) {
- // Convert stack slot to an SP offset
- // The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value
- // so we must add it in here.
- int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
- opr = LIR_OprFact::address(new LIR_Address(SP_opr, st_off + STACK_BIAS, type));
- } else if (r_1->is_Register()) {
- Register reg = r_1->as_Register();
- if (outgoing) {
- assert(!reg->is_in(), "should be using I regs");
- } else {
- assert(!reg->is_out(), "should be using O regs");
- }
- if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) {
- opr = as_long_opr(reg);
- } else if (is_reference_type(type)) {
- opr = as_oop_opr(reg);
- } else if (type == T_METADATA) {
- opr = as_metadata_opr(reg);
- } else if (type == T_ADDRESS) {
- opr = as_address_opr(reg);
- } else {
- opr = as_opr(reg);
- }
- } else if (r_1->is_FloatRegister()) {
- assert(type == T_DOUBLE || type == T_FLOAT, "wrong type");
- FloatRegister f = r_1->as_FloatRegister();
- if (type == T_DOUBLE) {
- opr = as_double_opr(f);
- } else {
- opr = as_float_opr(f);
- }
- }
- return opr;
-}
-
-// FrameMap
-//--------------------------------------------------------
-
-FloatRegister FrameMap::_fpu_regs [FrameMap::nof_fpu_regs];
-
-// some useful constant RInfo's:
-LIR_Opr FrameMap::in_long_opr;
-LIR_Opr FrameMap::out_long_opr;
-LIR_Opr FrameMap::g1_long_single_opr;
-
-LIR_Opr FrameMap::F0_opr;
-LIR_Opr FrameMap::F0_double_opr;
-
-LIR_Opr FrameMap::G0_opr;
-LIR_Opr FrameMap::G1_opr;
-LIR_Opr FrameMap::G2_opr;
-LIR_Opr FrameMap::G3_opr;
-LIR_Opr FrameMap::G4_opr;
-LIR_Opr FrameMap::G5_opr;
-LIR_Opr FrameMap::G6_opr;
-LIR_Opr FrameMap::G7_opr;
-LIR_Opr FrameMap::O0_opr;
-LIR_Opr FrameMap::O1_opr;
-LIR_Opr FrameMap::O2_opr;
-LIR_Opr FrameMap::O3_opr;
-LIR_Opr FrameMap::O4_opr;
-LIR_Opr FrameMap::O5_opr;
-LIR_Opr FrameMap::O6_opr;
-LIR_Opr FrameMap::O7_opr;
-LIR_Opr FrameMap::L0_opr;
-LIR_Opr FrameMap::L1_opr;
-LIR_Opr FrameMap::L2_opr;
-LIR_Opr FrameMap::L3_opr;
-LIR_Opr FrameMap::L4_opr;
-LIR_Opr FrameMap::L5_opr;
-LIR_Opr FrameMap::L6_opr;
-LIR_Opr FrameMap::L7_opr;
-LIR_Opr FrameMap::I0_opr;
-LIR_Opr FrameMap::I1_opr;
-LIR_Opr FrameMap::I2_opr;
-LIR_Opr FrameMap::I3_opr;
-LIR_Opr FrameMap::I4_opr;
-LIR_Opr FrameMap::I5_opr;
-LIR_Opr FrameMap::I6_opr;
-LIR_Opr FrameMap::I7_opr;
-
-LIR_Opr FrameMap::G0_oop_opr;
-LIR_Opr FrameMap::G1_oop_opr;
-LIR_Opr FrameMap::G2_oop_opr;
-LIR_Opr FrameMap::G3_oop_opr;
-LIR_Opr FrameMap::G4_oop_opr;
-LIR_Opr FrameMap::G5_oop_opr;
-LIR_Opr FrameMap::G6_oop_opr;
-LIR_Opr FrameMap::G7_oop_opr;
-LIR_Opr FrameMap::O0_oop_opr;
-LIR_Opr FrameMap::O1_oop_opr;
-LIR_Opr FrameMap::O2_oop_opr;
-LIR_Opr FrameMap::O3_oop_opr;
-LIR_Opr FrameMap::O4_oop_opr;
-LIR_Opr FrameMap::O5_oop_opr;
-LIR_Opr FrameMap::O6_oop_opr;
-LIR_Opr FrameMap::O7_oop_opr;
-LIR_Opr FrameMap::L0_oop_opr;
-LIR_Opr FrameMap::L1_oop_opr;
-LIR_Opr FrameMap::L2_oop_opr;
-LIR_Opr FrameMap::L3_oop_opr;
-LIR_Opr FrameMap::L4_oop_opr;
-LIR_Opr FrameMap::L5_oop_opr;
-LIR_Opr FrameMap::L6_oop_opr;
-LIR_Opr FrameMap::L7_oop_opr;
-LIR_Opr FrameMap::I0_oop_opr;
-LIR_Opr FrameMap::I1_oop_opr;
-LIR_Opr FrameMap::I2_oop_opr;
-LIR_Opr FrameMap::I3_oop_opr;
-LIR_Opr FrameMap::I4_oop_opr;
-LIR_Opr FrameMap::I5_oop_opr;
-LIR_Opr FrameMap::I6_oop_opr;
-LIR_Opr FrameMap::I7_oop_opr;
-
-LIR_Opr FrameMap::G0_metadata_opr;
-LIR_Opr FrameMap::G1_metadata_opr;
-LIR_Opr FrameMap::G2_metadata_opr;
-LIR_Opr FrameMap::G3_metadata_opr;
-LIR_Opr FrameMap::G4_metadata_opr;
-LIR_Opr FrameMap::G5_metadata_opr;
-LIR_Opr FrameMap::G6_metadata_opr;
-LIR_Opr FrameMap::G7_metadata_opr;
-LIR_Opr FrameMap::O0_metadata_opr;
-LIR_Opr FrameMap::O1_metadata_opr;
-LIR_Opr FrameMap::O2_metadata_opr;
-LIR_Opr FrameMap::O3_metadata_opr;
-LIR_Opr FrameMap::O4_metadata_opr;
-LIR_Opr FrameMap::O5_metadata_opr;
-LIR_Opr FrameMap::O6_metadata_opr;
-LIR_Opr FrameMap::O7_metadata_opr;
-LIR_Opr FrameMap::L0_metadata_opr;
-LIR_Opr FrameMap::L1_metadata_opr;
-LIR_Opr FrameMap::L2_metadata_opr;
-LIR_Opr FrameMap::L3_metadata_opr;
-LIR_Opr FrameMap::L4_metadata_opr;
-LIR_Opr FrameMap::L5_metadata_opr;
-LIR_Opr FrameMap::L6_metadata_opr;
-LIR_Opr FrameMap::L7_metadata_opr;
-LIR_Opr FrameMap::I0_metadata_opr;
-LIR_Opr FrameMap::I1_metadata_opr;
-LIR_Opr FrameMap::I2_metadata_opr;
-LIR_Opr FrameMap::I3_metadata_opr;
-LIR_Opr FrameMap::I4_metadata_opr;
-LIR_Opr FrameMap::I5_metadata_opr;
-LIR_Opr FrameMap::I6_metadata_opr;
-LIR_Opr FrameMap::I7_metadata_opr;
-
-LIR_Opr FrameMap::SP_opr;
-LIR_Opr FrameMap::FP_opr;
-
-LIR_Opr FrameMap::Oexception_opr;
-LIR_Opr FrameMap::Oissuing_pc_opr;
-
-LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, };
-LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, };
-
-
-FloatRegister FrameMap::nr2floatreg (int rnr) {
- assert(_init_done, "tables not initialized");
- debug_only(fpu_range_check(rnr);)
- return _fpu_regs[rnr];
-}
-
-
-// returns true if reg could be smashed by a callee.
-bool FrameMap::is_caller_save_register (LIR_Opr reg) {
- if (reg->is_single_fpu() || reg->is_double_fpu()) { return true; }
- if (reg->is_double_cpu()) {
- return is_caller_save_register(reg->as_register_lo()) ||
- is_caller_save_register(reg->as_register_hi());
- }
- return is_caller_save_register(reg->as_register());
-}
-
-
-NEEDS_CLEANUP // once the new calling convention is enabled, we no
- // longer need to treat I5, I4 and L0 specially
-// Because the interpreter destroys caller's I5, I4 and L0,
-// we must spill them before doing a Java call as we may land in
-// interpreter.
-bool FrameMap::is_caller_save_register (Register r) {
- return (r->is_global() && (r != G0)) || r->is_out();
-}
-
-
-void FrameMap::initialize() {
- assert(!_init_done, "once");
-
- int i=0;
- // Register usage:
- // O6: sp
- // I6: fp
- // I7: return address
- // G0: zero
- // G2: thread
- // G7: not available
- // G6: not available
- /* 0 */ map_register(i++, L0);
- /* 1 */ map_register(i++, L1);
- /* 2 */ map_register(i++, L2);
- /* 3 */ map_register(i++, L3);
- /* 4 */ map_register(i++, L4);
- /* 5 */ map_register(i++, L5);
- /* 6 */ map_register(i++, L6);
- /* 7 */ map_register(i++, L7);
-
- /* 8 */ map_register(i++, I0);
- /* 9 */ map_register(i++, I1);
- /* 10 */ map_register(i++, I2);
- /* 11 */ map_register(i++, I3);
- /* 12 */ map_register(i++, I4);
- /* 13 */ map_register(i++, I5);
- /* 14 */ map_register(i++, O0);
- /* 15 */ map_register(i++, O1);
- /* 16 */ map_register(i++, O2);
- /* 17 */ map_register(i++, O3);
- /* 18 */ map_register(i++, O4);
- /* 19 */ map_register(i++, O5); // <- last register visible in RegAlloc (RegAlloc::nof+cpu_regs)
- /* 20 */ map_register(i++, G1);
- /* 21 */ map_register(i++, G3);
- /* 22 */ map_register(i++, G4);
- /* 23 */ map_register(i++, G5);
- /* 24 */ map_register(i++, G0);
-
- // the following registers are not normally available
- /* 25 */ map_register(i++, O7);
- /* 26 */ map_register(i++, G2);
- /* 27 */ map_register(i++, O6);
- /* 28 */ map_register(i++, I6);
- /* 29 */ map_register(i++, I7);
- /* 30 */ map_register(i++, G6);
- /* 31 */ map_register(i++, G7);
- assert(i == nof_cpu_regs, "number of CPU registers");
-
- for (i = 0; i < nof_fpu_regs; i++) {
- _fpu_regs[i] = as_FloatRegister(i);
- }
-
- _init_done = true;
-
- in_long_opr = as_long_opr(I0);
- out_long_opr = as_long_opr(O0);
- g1_long_single_opr = as_long_single_opr(G1);
-
- G0_opr = as_opr(G0);
- G1_opr = as_opr(G1);
- G2_opr = as_opr(G2);
- G3_opr = as_opr(G3);
- G4_opr = as_opr(G4);
- G5_opr = as_opr(G5);
- G6_opr = as_opr(G6);
- G7_opr = as_opr(G7);
- O0_opr = as_opr(O0);
- O1_opr = as_opr(O1);
- O2_opr = as_opr(O2);
- O3_opr = as_opr(O3);
- O4_opr = as_opr(O4);
- O5_opr = as_opr(O5);
- O6_opr = as_opr(O6);
- O7_opr = as_opr(O7);
- L0_opr = as_opr(L0);
- L1_opr = as_opr(L1);
- L2_opr = as_opr(L2);
- L3_opr = as_opr(L3);
- L4_opr = as_opr(L4);
- L5_opr = as_opr(L5);
- L6_opr = as_opr(L6);
- L7_opr = as_opr(L7);
- I0_opr = as_opr(I0);
- I1_opr = as_opr(I1);
- I2_opr = as_opr(I2);
- I3_opr = as_opr(I3);
- I4_opr = as_opr(I4);
- I5_opr = as_opr(I5);
- I6_opr = as_opr(I6);
- I7_opr = as_opr(I7);
-
- G0_oop_opr = as_oop_opr(G0);
- G1_oop_opr = as_oop_opr(G1);
- G2_oop_opr = as_oop_opr(G2);
- G3_oop_opr = as_oop_opr(G3);
- G4_oop_opr = as_oop_opr(G4);
- G5_oop_opr = as_oop_opr(G5);
- G6_oop_opr = as_oop_opr(G6);
- G7_oop_opr = as_oop_opr(G7);
- O0_oop_opr = as_oop_opr(O0);
- O1_oop_opr = as_oop_opr(O1);
- O2_oop_opr = as_oop_opr(O2);
- O3_oop_opr = as_oop_opr(O3);
- O4_oop_opr = as_oop_opr(O4);
- O5_oop_opr = as_oop_opr(O5);
- O6_oop_opr = as_oop_opr(O6);
- O7_oop_opr = as_oop_opr(O7);
- L0_oop_opr = as_oop_opr(L0);
- L1_oop_opr = as_oop_opr(L1);
- L2_oop_opr = as_oop_opr(L2);
- L3_oop_opr = as_oop_opr(L3);
- L4_oop_opr = as_oop_opr(L4);
- L5_oop_opr = as_oop_opr(L5);
- L6_oop_opr = as_oop_opr(L6);
- L7_oop_opr = as_oop_opr(L7);
- I0_oop_opr = as_oop_opr(I0);
- I1_oop_opr = as_oop_opr(I1);
- I2_oop_opr = as_oop_opr(I2);
- I3_oop_opr = as_oop_opr(I3);
- I4_oop_opr = as_oop_opr(I4);
- I5_oop_opr = as_oop_opr(I5);
- I6_oop_opr = as_oop_opr(I6);
- I7_oop_opr = as_oop_opr(I7);
-
- G0_metadata_opr = as_metadata_opr(G0);
- G1_metadata_opr = as_metadata_opr(G1);
- G2_metadata_opr = as_metadata_opr(G2);
- G3_metadata_opr = as_metadata_opr(G3);
- G4_metadata_opr = as_metadata_opr(G4);
- G5_metadata_opr = as_metadata_opr(G5);
- G6_metadata_opr = as_metadata_opr(G6);
- G7_metadata_opr = as_metadata_opr(G7);
- O0_metadata_opr = as_metadata_opr(O0);
- O1_metadata_opr = as_metadata_opr(O1);
- O2_metadata_opr = as_metadata_opr(O2);
- O3_metadata_opr = as_metadata_opr(O3);
- O4_metadata_opr = as_metadata_opr(O4);
- O5_metadata_opr = as_metadata_opr(O5);
- O6_metadata_opr = as_metadata_opr(O6);
- O7_metadata_opr = as_metadata_opr(O7);
- L0_metadata_opr = as_metadata_opr(L0);
- L1_metadata_opr = as_metadata_opr(L1);
- L2_metadata_opr = as_metadata_opr(L2);
- L3_metadata_opr = as_metadata_opr(L3);
- L4_metadata_opr = as_metadata_opr(L4);
- L5_metadata_opr = as_metadata_opr(L5);
- L6_metadata_opr = as_metadata_opr(L6);
- L7_metadata_opr = as_metadata_opr(L7);
- I0_metadata_opr = as_metadata_opr(I0);
- I1_metadata_opr = as_metadata_opr(I1);
- I2_metadata_opr = as_metadata_opr(I2);
- I3_metadata_opr = as_metadata_opr(I3);
- I4_metadata_opr = as_metadata_opr(I4);
- I5_metadata_opr = as_metadata_opr(I5);
- I6_metadata_opr = as_metadata_opr(I6);
- I7_metadata_opr = as_metadata_opr(I7);
-
- FP_opr = as_pointer_opr(FP);
- SP_opr = as_pointer_opr(SP);
-
- F0_opr = as_float_opr(F0);
- F0_double_opr = as_double_opr(F0);
-
- Oexception_opr = as_oop_opr(Oexception);
- Oissuing_pc_opr = as_opr(Oissuing_pc);
-
- _caller_save_cpu_regs[0] = FrameMap::O0_opr;
- _caller_save_cpu_regs[1] = FrameMap::O1_opr;
- _caller_save_cpu_regs[2] = FrameMap::O2_opr;
- _caller_save_cpu_regs[3] = FrameMap::O3_opr;
- _caller_save_cpu_regs[4] = FrameMap::O4_opr;
- _caller_save_cpu_regs[5] = FrameMap::O5_opr;
- _caller_save_cpu_regs[6] = FrameMap::G1_opr;
- _caller_save_cpu_regs[7] = FrameMap::G3_opr;
- _caller_save_cpu_regs[8] = FrameMap::G4_opr;
- _caller_save_cpu_regs[9] = FrameMap::G5_opr;
- for (int i = 0; i < nof_caller_save_fpu_regs; i++) {
- _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i);
- }
-}
-
-
-Address FrameMap::make_new_address(ByteSize sp_offset) const {
- return Address(SP, STACK_BIAS + in_bytes(sp_offset));
-}
-
-
-VMReg FrameMap::fpu_regname (int n) {
- return as_FloatRegister(n)->as_VMReg();
-}
-
-
-LIR_Opr FrameMap::stack_pointer() {
- return SP_opr;
-}
-
-
-// JSR 292
-LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
- assert(L7 == L7_mh_SP_save, "must be same register");
- return L7_opr;
-}
-
-
-bool FrameMap::validate_frame() {
- int max_offset = in_bytes(framesize_in_bytes());
- int java_index = 0;
- for (int i = 0; i < _incoming_arguments->length(); i++) {
- LIR_Opr opr = _incoming_arguments->at(i);
- if (opr->is_stack()) {
- max_offset = MAX2(_argument_locations->at(java_index), max_offset);
- }
- java_index += type2size[opr->type()];
- }
- return Assembler::is_simm13(max_offset + STACK_BIAS);
-}
diff --git a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.hpp b/src/hotspot/cpu/sparc/c1_FrameMap_sparc.hpp
deleted file mode 100644
index aec9611d38d..00000000000
--- a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.hpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C1_FRAMEMAP_SPARC_HPP
-#define CPU_SPARC_C1_FRAMEMAP_SPARC_HPP
-
- public:
-
- enum {
- nof_reg_args = 6, // registers o0-o5 are available for parameter passing
- first_available_sp_in_frame = frame::memory_parameter_word_sp_offset * BytesPerWord,
- frame_pad_in_bytes = 0
- };
-
- static const int pd_c_runtime_reserved_arg_size;
-
- static LIR_Opr G0_opr;
- static LIR_Opr G1_opr;
- static LIR_Opr G2_opr;
- static LIR_Opr G3_opr;
- static LIR_Opr G4_opr;
- static LIR_Opr G5_opr;
- static LIR_Opr G6_opr;
- static LIR_Opr G7_opr;
- static LIR_Opr O0_opr;
- static LIR_Opr O1_opr;
- static LIR_Opr O2_opr;
- static LIR_Opr O3_opr;
- static LIR_Opr O4_opr;
- static LIR_Opr O5_opr;
- static LIR_Opr O6_opr;
- static LIR_Opr O7_opr;
- static LIR_Opr L0_opr;
- static LIR_Opr L1_opr;
- static LIR_Opr L2_opr;
- static LIR_Opr L3_opr;
- static LIR_Opr L4_opr;
- static LIR_Opr L5_opr;
- static LIR_Opr L6_opr;
- static LIR_Opr L7_opr;
- static LIR_Opr I0_opr;
- static LIR_Opr I1_opr;
- static LIR_Opr I2_opr;
- static LIR_Opr I3_opr;
- static LIR_Opr I4_opr;
- static LIR_Opr I5_opr;
- static LIR_Opr I6_opr;
- static LIR_Opr I7_opr;
-
- static LIR_Opr SP_opr;
- static LIR_Opr FP_opr;
-
- static LIR_Opr G0_oop_opr;
- static LIR_Opr G1_oop_opr;
- static LIR_Opr G2_oop_opr;
- static LIR_Opr G3_oop_opr;
- static LIR_Opr G4_oop_opr;
- static LIR_Opr G5_oop_opr;
- static LIR_Opr G6_oop_opr;
- static LIR_Opr G7_oop_opr;
- static LIR_Opr O0_oop_opr;
- static LIR_Opr O1_oop_opr;
- static LIR_Opr O2_oop_opr;
- static LIR_Opr O3_oop_opr;
- static LIR_Opr O4_oop_opr;
- static LIR_Opr O5_oop_opr;
- static LIR_Opr O6_oop_opr;
- static LIR_Opr O7_oop_opr;
- static LIR_Opr L0_oop_opr;
- static LIR_Opr L1_oop_opr;
- static LIR_Opr L2_oop_opr;
- static LIR_Opr L3_oop_opr;
- static LIR_Opr L4_oop_opr;
- static LIR_Opr L5_oop_opr;
- static LIR_Opr L6_oop_opr;
- static LIR_Opr L7_oop_opr;
- static LIR_Opr I0_oop_opr;
- static LIR_Opr I1_oop_opr;
- static LIR_Opr I2_oop_opr;
- static LIR_Opr I3_oop_opr;
- static LIR_Opr I4_oop_opr;
- static LIR_Opr I5_oop_opr;
- static LIR_Opr I6_oop_opr;
- static LIR_Opr I7_oop_opr;
-
- static LIR_Opr G0_metadata_opr;
- static LIR_Opr G1_metadata_opr;
- static LIR_Opr G2_metadata_opr;
- static LIR_Opr G3_metadata_opr;
- static LIR_Opr G4_metadata_opr;
- static LIR_Opr G5_metadata_opr;
- static LIR_Opr G6_metadata_opr;
- static LIR_Opr G7_metadata_opr;
- static LIR_Opr O0_metadata_opr;
- static LIR_Opr O1_metadata_opr;
- static LIR_Opr O2_metadata_opr;
- static LIR_Opr O3_metadata_opr;
- static LIR_Opr O4_metadata_opr;
- static LIR_Opr O5_metadata_opr;
- static LIR_Opr O6_metadata_opr;
- static LIR_Opr O7_metadata_opr;
- static LIR_Opr L0_metadata_opr;
- static LIR_Opr L1_metadata_opr;
- static LIR_Opr L2_metadata_opr;
- static LIR_Opr L3_metadata_opr;
- static LIR_Opr L4_metadata_opr;
- static LIR_Opr L5_metadata_opr;
- static LIR_Opr L6_metadata_opr;
- static LIR_Opr L7_metadata_opr;
- static LIR_Opr I0_metadata_opr;
- static LIR_Opr I1_metadata_opr;
- static LIR_Opr I2_metadata_opr;
- static LIR_Opr I3_metadata_opr;
- static LIR_Opr I4_metadata_opr;
- static LIR_Opr I5_metadata_opr;
- static LIR_Opr I6_metadata_opr;
- static LIR_Opr I7_metadata_opr;
-
- static LIR_Opr in_long_opr;
- static LIR_Opr out_long_opr;
- static LIR_Opr g1_long_single_opr;
-
- static LIR_Opr F0_opr;
- static LIR_Opr F0_double_opr;
-
- static LIR_Opr Oexception_opr;
- static LIR_Opr Oissuing_pc_opr;
-
- private:
- static FloatRegister _fpu_regs [nof_fpu_regs];
-
- static LIR_Opr as_long_single_opr(Register r) {
- return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r));
- }
- static LIR_Opr as_long_pair_opr(Register r) {
- return LIR_OprFact::double_cpu(cpu_reg2rnr(r->successor()), cpu_reg2rnr(r));
- }
-
- public:
-
- static LIR_Opr as_long_opr(Register r) {
- return as_long_single_opr(r);
- }
- static LIR_Opr as_pointer_opr(Register r) {
- return as_long_single_opr(r);
- }
- static LIR_Opr as_float_opr(FloatRegister r) {
- return LIR_OprFact::single_fpu(r->encoding());
- }
- static LIR_Opr as_double_opr(FloatRegister r) {
- return LIR_OprFact::double_fpu(r->successor()->encoding(), r->encoding());
- }
-
- static FloatRegister nr2floatreg (int rnr);
-
- static VMReg fpu_regname (int n);
-
- static bool is_caller_save_register (LIR_Opr reg);
- static bool is_caller_save_register (Register r);
-
- static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; }
- static int last_cpu_reg() { return pd_last_cpu_reg; }
-
-#endif // CPU_SPARC_C1_FRAMEMAP_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp
deleted file mode 100644
index e76fa154a71..00000000000
--- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp
+++ /dev/null
@@ -1,3358 +0,0 @@
-/*
- * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "asm/macroAssembler.inline.hpp"
-#include "c1/c1_Compilation.hpp"
-#include "c1/c1_LIRAssembler.hpp"
-#include "c1/c1_MacroAssembler.hpp"
-#include "c1/c1_Runtime1.hpp"
-#include "c1/c1_ValueStack.hpp"
-#include "ci/ciArrayKlass.hpp"
-#include "ci/ciInstance.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "memory/universe.hpp"
-#include "nativeInst_sparc.hpp"
-#include "oops/objArrayKlass.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/jniHandles.inline.hpp"
-#include "runtime/safepointMechanism.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "utilities/powerOfTwo.hpp"
-
-#define __ _masm->
-
-
-//------------------------------------------------------------
-
-
-bool LIR_Assembler::is_small_constant(LIR_Opr opr) {
- if (opr->is_constant()) {
- LIR_Const* constant = opr->as_constant_ptr();
- switch (constant->type()) {
- case T_INT: {
- jint value = constant->as_jint();
- return Assembler::is_simm13(value);
- }
-
- default:
- return false;
- }
- }
- return false;
-}
-
-
-bool LIR_Assembler::is_single_instruction(LIR_Op* op) {
- switch (op->code()) {
- case lir_null_check:
- return true;
-
-
- case lir_add:
- case lir_ushr:
- case lir_shr:
- case lir_shl:
- // integer shifts and adds are always one instruction
- return op->result_opr()->is_single_cpu();
-
-
- case lir_move: {
- LIR_Op1* op1 = op->as_Op1();
- LIR_Opr src = op1->in_opr();
- LIR_Opr dst = op1->result_opr();
-
- if (src == dst) {
- NEEDS_CLEANUP;
- // this works around a problem where moves with the same src and dst
- // end up in the delay slot and then the assembler swallows the mov
- // since it has no effect and then it complains because the delay slot
- // is empty. returning false stops the optimizer from putting this in
- // the delay slot
- return false;
- }
-
- // don't put moves involving oops into the delay slot since the VerifyOops code
- // will make it much larger than a single instruction.
- if (VerifyOops) {
- return false;
- }
-
- if (src->is_double_cpu() || dst->is_double_cpu() || op1->patch_code() != lir_patch_none ||
- ((src->is_double_fpu() || dst->is_double_fpu()) && op1->move_kind() != lir_move_normal)) {
- return false;
- }
-
- if (UseCompressedOops) {
- if (dst->is_address() && !dst->is_stack() && is_reference_type(dst->type())) return false;
- if (src->is_address() && !src->is_stack() && is_reference_type(src->type())) return false;
- }
-
- if (UseCompressedClassPointers) {
- if (src->is_address() && !src->is_stack() && src->type() == T_ADDRESS &&
- src->as_address_ptr()->disp() == oopDesc::klass_offset_in_bytes()) return false;
- }
-
- if (dst->is_register()) {
- if (src->is_address() && Assembler::is_simm13(src->as_address_ptr()->disp())) {
- return !PatchALot;
- } else if (src->is_single_stack()) {
- return true;
- }
- }
-
- if (src->is_register()) {
- if (dst->is_address() && Assembler::is_simm13(dst->as_address_ptr()->disp())) {
- return !PatchALot;
- } else if (dst->is_single_stack()) {
- return true;
- }
- }
-
- if (dst->is_register() &&
- ((src->is_register() && src->is_single_word() && src->is_same_type(dst)) ||
- (src->is_constant() && LIR_Assembler::is_small_constant(op->as_Op1()->in_opr())))) {
- return true;
- }
-
- return false;
- }
-
- default:
- return false;
- }
- ShouldNotReachHere();
-}
-
-
-LIR_Opr LIR_Assembler::receiverOpr() {
- return FrameMap::O0_oop_opr;
-}
-
-
-LIR_Opr LIR_Assembler::osrBufferPointer() {
- return FrameMap::I0_opr;
-}
-
-
-int LIR_Assembler::initial_frame_size_in_bytes() const {
- return in_bytes(frame_map()->framesize_in_bytes());
-}
-
-
-// inline cache check: the inline cached class is in G5_inline_cache_reg(G5);
-// we fetch the class of the receiver (O0) 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(O0, G5_inline_cache_reg);
- return offset;
-}
-
-void LIR_Assembler::clinit_barrier(ciMethod* method) {
- ShouldNotReachHere(); // not implemented
-}
-
-void LIR_Assembler::osr_entry() {
- // On-stack-replacement entry sequence (interpreter frame layout described in interpreter_sparc.cpp):
- //
- // 1. Create a new compiled activation.
- // 2. Initialize local variables in the compiled activation. The expression stack must be empty
- // at the osr_bci; it is not initialized.
- // 3. Jump to the continuation address in compiled code to resume execution.
-
- // OSR entry point
- offsets()->set_value(CodeOffsets::OSR_Entry, code_offset());
- BlockBegin* osr_entry = compilation()->hir()->osr_entry();
- ValueStack* entry_state = osr_entry->end()->state();
- int number_of_locks = entry_state->locks_size();
-
- // Create a frame for the compiled activation.
- __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes());
-
- // OSR buffer is
- //
- // locals[nlocals-1..0]
- // monitors[number_of_locks-1..0]
- //
- // locals is a direct copy of the interpreter frame so in the osr buffer
- // so first slot in the local array is the last local from the interpreter
- // and last slot is local[0] (receiver) from the interpreter
- //
- // Similarly with locks. The first lock slot in the osr buffer is the nth lock
- // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock
- // in the interpreter frame (the method lock if a sync method)
-
- // Initialize monitors in the compiled activation.
- // I0: pointer to osr buffer
- //
- // All other registers are dead at this point and the locals will be
- // copied into place by code emitted in the IR.
-
- Register OSR_buf = osrBufferPointer()->as_register();
- { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
- int monitor_offset = BytesPerWord * method()->max_locals() +
- (2 * BytesPerWord) * (number_of_locks - 1);
- // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in
- // the OSR buffer using 2 word entries: first the lock and then
- // the oop.
- for (int i = 0; i < number_of_locks; i++) {
- int slot_offset = monitor_offset - ((i * 2) * BytesPerWord);
-#ifdef ASSERT
- // verify the interpreter's monitor has a non-null object
- {
- Label L;
- __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7);
- __ cmp_and_br_short(O7, G0, Assembler::notEqual, Assembler::pt, L);
- __ stop("locked object is NULL");
- __ bind(L);
- }
-#endif // ASSERT
- // Copy the lock field into the compiled activation.
- __ ld_ptr(OSR_buf, slot_offset + 0, O7);
- __ st_ptr(O7, frame_map()->address_for_monitor_lock(i));
- __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7);
- __ st_ptr(O7, frame_map()->address_for_monitor_object(i));
- }
- }
-}
-
-
-// --------------------------------------------------------------------------------------------
-
-void LIR_Assembler::monitorexit(LIR_Opr obj_opr, LIR_Opr lock_opr, Register hdr, int monitor_no) {
- if (!GenerateSynchronizationCode) return;
-
- Register obj_reg = obj_opr->as_register();
- Register lock_reg = lock_opr->as_register();
-
- Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no);
- Register reg = mon_addr.base();
- int offset = mon_addr.disp();
- // compute pointer to BasicLock
- if (mon_addr.is_simm13()) {
- __ add(reg, offset, lock_reg);
- }
- else {
- __ set(offset, lock_reg);
- __ add(reg, lock_reg, lock_reg);
- }
- // unlock object
- MonitorAccessStub* slow_case = new MonitorExitStub(lock_opr, UseFastLocking, monitor_no);
- // _slow_case_stubs->append(slow_case);
- // temporary fix: must be created after exceptionhandler, therefore as call stub
- _slow_case_stubs->append(slow_case);
- if (UseFastLocking) {
- // try inlined fast unlocking first, revert to slow locking if it fails
- // note: lock_reg points to the displaced header since the displaced header offset is 0!
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
- __ unlock_object(hdr, obj_reg, lock_reg, *slow_case->entry());
- } else {
- // always do slow unlocking
- // note: the slow unlocking code could be inlined here, however if we use
- // slow unlocking, speed doesn't matter anyway and this solution is
- // simpler and requires less duplicated code - additionally, the
- // slow unlocking code is the same in either case which simplifies
- // debugging
- __ br(Assembler::always, false, Assembler::pt, *slow_case->entry());
- __ delayed()->nop();
- }
- // done
- __ bind(*slow_case->continuation());
-}
-
-
-int LIR_Assembler::emit_exception_handler() {
- // if the last instruction is a call (typically to do a throw which
- // is coming at the end after block reordering) the return address
- // must still point into the code area in order to avoid assertion
- // failures when searching for the corresponding bci => add a nop
- // (was bug 5/14/1999 - gri)
- __ nop();
-
- // generate code for exception handler
- ciMethod* method = compilation()->method();
-
- address handler_base = __ start_a_stub(exception_handler_size());
-
- if (handler_base == NULL) {
- // not enough space left for the handler
- bailout("exception handler overflow");
- return -1;
- }
-
- int offset = code_offset();
-
- __ call(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- __ should_not_reach_here();
- guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
- __ end_a_stub();
-
- return offset;
-}
-
-
-// Emit the code to remove the frame from the stack in the exception
-// unwind path.
-int LIR_Assembler::emit_unwind_handler() {
-#ifndef PRODUCT
- if (CommentedAssembly) {
- _masm->block_comment("Unwind handler");
- }
-#endif
-
- int offset = code_offset();
-
- // Fetch the exception from TLS and clear out exception related thread state
- __ ld_ptr(G2_thread, in_bytes(JavaThread::exception_oop_offset()), O0);
- __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_oop_offset()));
- __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_pc_offset()));
-
- __ bind(_unwind_handler_entry);
- __ verify_not_null_oop(O0);
- if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) {
- __ mov(O0, I0); // Preserve the exception
- }
-
- // Preform needed unlocking
- MonitorExitStub* stub = NULL;
- if (method()->is_synchronized()) {
- monitor_address(0, FrameMap::I1_opr);
- stub = new MonitorExitStub(FrameMap::I1_opr, true, 0);
- __ unlock_object(I3, I2, I1, *stub->entry());
- __ bind(*stub->continuation());
- }
-
- if (compilation()->env()->dtrace_method_probes()) {
- __ mov(G2_thread, O0);
- __ save_thread(I1); // need to preserve thread in G2 across
- // runtime call
- metadata2reg(method()->constant_encoding(), O1);
- __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), relocInfo::runtime_call_type);
- __ delayed()->nop();
- __ restore_thread(I1);
- }
-
- if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) {
- __ mov(I0, O0); // Restore the exception
- }
-
- // dispatch to the unwind logic
- __ call(Runtime1::entry_for(Runtime1::unwind_exception_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
-
- // Emit the slow path assembly
- if (stub != NULL) {
- stub->emit_code(this);
- }
-
- return offset;
-}
-
-
-int LIR_Assembler::emit_deopt_handler() {
- // if the last instruction is a call (typically to do a throw which
- // is coming at the end after block reordering) the return address
- // must still point into the code area in order to avoid assertion
- // failures when searching for the corresponding bci => add a nop
- // (was bug 5/14/1999 - gri)
- __ nop();
-
- // generate code for deopt handler
- ciMethod* method = compilation()->method();
- address handler_base = __ start_a_stub(deopt_handler_size());
- if (handler_base == NULL) {
- // not enough space left for the handler
- bailout("deopt handler overflow");
- return -1;
- }
-
- int offset = code_offset();
- AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack());
- __ JUMP(deopt_blob, G3_scratch, 0); // sethi;jmp
- __ delayed()->nop();
- guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
- __ end_a_stub();
-
- return offset;
-}
-
-
-void LIR_Assembler::jobject2reg(jobject o, Register reg) {
- if (o == NULL) {
- __ set(NULL_WORD, reg);
- } else {
-#ifdef ASSERT
- {
- ThreadInVMfromNative tiv(JavaThread::current());
- assert(Universe::heap()->is_in(JNIHandles::resolve(o)), "should be real oop");
- }
-#endif
- int oop_index = __ oop_recorder()->find_index(o);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
- __ set(NULL_WORD, reg, rspec); // Will be set when the nmethod is created
- }
-}
-
-
-void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) {
- // Allocate a new index in table to hold the object once it's been patched
- int oop_index = __ oop_recorder()->allocate_oop_index(NULL);
- PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index);
-
- AddressLiteral addrlit(NULL, oop_Relocation::spec(oop_index));
- assert(addrlit.rspec().type() == relocInfo::oop_type, "must be an oop reloc");
- // It may not seem necessary to use a sethi/add pair to load a NULL into dest, but the
- // NULL will be dynamically patched later and the patched value may be large. We must
- // therefore generate the sethi/add as a placeholders
- __ patchable_set(addrlit, reg);
-
- patching_epilog(patch, lir_patch_normal, reg, info);
-}
-
-
-void LIR_Assembler::metadata2reg(Metadata* o, Register reg) {
- __ set_metadata_constant(o, reg);
-}
-
-void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo *info) {
- // Allocate a new index in table to hold the klass once it's been patched
- int index = __ oop_recorder()->allocate_metadata_index(NULL);
- PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index);
- AddressLiteral addrlit(NULL, metadata_Relocation::spec(index));
- assert(addrlit.rspec().type() == relocInfo::metadata_type, "must be an metadata reloc");
- // It may not seem necessary to use a sethi/add pair to load a NULL into dest, but the
- // NULL will be dynamically patched later and the patched value may be large. We must
- // therefore generate the sethi/add as a placeholders
- __ patchable_set(addrlit, reg);
-
- patching_epilog(patch, lir_patch_normal, reg, info);
-}
-
-void LIR_Assembler::emit_op3(LIR_Op3* op) {
- switch (op->code()) {
- case lir_idiv:
- case lir_irem: // Both idiv & irem are handled after the switch (below).
- break;
- case lir_fmaf:
- __ fmadd(FloatRegisterImpl::S,
- op->in_opr1()->as_float_reg(),
- op->in_opr2()->as_float_reg(),
- op->in_opr3()->as_float_reg(),
- op->result_opr()->as_float_reg());
- return;
- case lir_fmad:
- __ fmadd(FloatRegisterImpl::D,
- op->in_opr1()->as_double_reg(),
- op->in_opr2()->as_double_reg(),
- op->in_opr3()->as_double_reg(),
- op->result_opr()->as_double_reg());
- return;
- default:
- ShouldNotReachHere();
- break;
- }
-
- // Handle idiv & irem:
-
- Register Rdividend = op->in_opr1()->as_register();
- Register Rdivisor = noreg;
- Register Rscratch = op->in_opr3()->as_register();
- Register Rresult = op->result_opr()->as_register();
- int divisor = -1;
-
- if (op->in_opr2()->is_register()) {
- Rdivisor = op->in_opr2()->as_register();
- } else {
- divisor = op->in_opr2()->as_constant_ptr()->as_jint();
- assert(Assembler::is_simm13(divisor), "can only handle simm13");
- }
-
- assert(Rdividend != Rscratch, "");
- assert(Rdivisor != Rscratch, "");
- assert(op->code() == lir_idiv || op->code() == lir_irem, "Must be irem or idiv");
-
- if (Rdivisor == noreg && is_power_of_2(divisor)) {
- // convert division by a power of two into some shifts and logical operations
- if (op->code() == lir_idiv) {
- if (divisor == 2) {
- __ srl(Rdividend, 31, Rscratch);
- } else {
- __ sra(Rdividend, 31, Rscratch);
- __ and3(Rscratch, divisor - 1, Rscratch);
- }
- __ add(Rdividend, Rscratch, Rscratch);
- __ sra(Rscratch, log2_int(divisor), Rresult);
- return;
- } else {
- if (divisor == 2) {
- __ srl(Rdividend, 31, Rscratch);
- } else {
- __ sra(Rdividend, 31, Rscratch);
- __ and3(Rscratch, divisor - 1,Rscratch);
- }
- __ add(Rdividend, Rscratch, Rscratch);
- __ andn(Rscratch, divisor - 1,Rscratch);
- __ sub(Rdividend, Rscratch, Rresult);
- return;
- }
- }
-
- __ sra(Rdividend, 31, Rscratch);
- __ wry(Rscratch);
-
- add_debug_info_for_div0_here(op->info());
-
- if (Rdivisor != noreg) {
- __ sdivcc(Rdividend, Rdivisor, (op->code() == lir_idiv ? Rresult : Rscratch));
- } else {
- assert(Assembler::is_simm13(divisor), "can only handle simm13");
- __ sdivcc(Rdividend, divisor, (op->code() == lir_idiv ? Rresult : Rscratch));
- }
-
- Label skip;
- __ br(Assembler::overflowSet, true, Assembler::pn, skip);
- __ delayed()->Assembler::sethi(0x80000000, (op->code() == lir_idiv ? Rresult : Rscratch));
- __ bind(skip);
-
- if (op->code() == lir_irem) {
- if (Rdivisor != noreg) {
- __ smul(Rscratch, Rdivisor, Rscratch);
- } else {
- __ smul(Rscratch, divisor, Rscratch);
- }
- __ sub(Rdividend, Rscratch, Rresult);
- }
-}
-
-
-void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) {
-#ifdef ASSERT
- assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label");
- if (op->block() != NULL) _branch_target_blocks.append(op->block());
- if (op->ublock() != NULL) _branch_target_blocks.append(op->ublock());
-#endif
- assert(op->info() == NULL, "shouldn't have CodeEmitInfo");
-
- if (op->cond() == lir_cond_always) {
- __ br(Assembler::always, false, Assembler::pt, *(op->label()));
- } else if (op->code() == lir_cond_float_branch) {
- assert(op->ublock() != NULL, "must have unordered successor");
- bool is_unordered = (op->ublock() == op->block());
- Assembler::Condition acond;
- switch (op->cond()) {
- case lir_cond_equal: acond = Assembler::f_equal; break;
- case lir_cond_notEqual: acond = Assembler::f_notEqual; break;
- case lir_cond_less: acond = (is_unordered ? Assembler::f_unorderedOrLess : Assembler::f_less); break;
- case lir_cond_greater: acond = (is_unordered ? Assembler::f_unorderedOrGreater : Assembler::f_greater); break;
- case lir_cond_lessEqual: acond = (is_unordered ? Assembler::f_unorderedOrLessOrEqual : Assembler::f_lessOrEqual); break;
- case lir_cond_greaterEqual: acond = (is_unordered ? Assembler::f_unorderedOrGreaterOrEqual: Assembler::f_greaterOrEqual); break;
- default : ShouldNotReachHere();
- }
- __ fb( acond, false, Assembler::pn, *(op->label()));
- } else {
- assert (op->code() == lir_branch, "just checking");
-
- Assembler::Condition acond;
- switch (op->cond()) {
- case lir_cond_equal: acond = Assembler::equal; break;
- case lir_cond_notEqual: acond = Assembler::notEqual; break;
- case lir_cond_less: acond = Assembler::less; break;
- case lir_cond_lessEqual: acond = Assembler::lessEqual; break;
- case lir_cond_greaterEqual: acond = Assembler::greaterEqual; break;
- case lir_cond_greater: acond = Assembler::greater; break;
- case lir_cond_aboveEqual: acond = Assembler::greaterEqualUnsigned; break;
- case lir_cond_belowEqual: acond = Assembler::lessEqualUnsigned; break;
- default: ShouldNotReachHere();
- };
-
- // sparc has different condition codes for testing 32-bit
- // vs. 64-bit values. We could always test xcc is we could
- // guarantee that 32-bit loads always sign extended but that isn't
- // true and since sign extension isn't free, it would impose a
- // slight cost.
- if (op->type() == T_INT) {
- __ br(acond, false, Assembler::pn, *(op->label()));
- } else
- __ brx(acond, false, Assembler::pn, *(op->label()));
- }
- // The peephole pass fills the delay slot
-}
-
-
-void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) {
- Bytecodes::Code code = op->bytecode();
- LIR_Opr dst = op->result_opr();
-
- switch(code) {
- case Bytecodes::_i2l: {
- Register rlo = dst->as_register_lo();
- Register rhi = dst->as_register_hi();
- Register rval = op->in_opr()->as_register();
- __ sra(rval, 0, rlo);
- break;
- }
- case Bytecodes::_i2d:
- case Bytecodes::_i2f: {
- bool is_double = (code == Bytecodes::_i2d);
- FloatRegister rdst = is_double ? dst->as_double_reg() : dst->as_float_reg();
- FloatRegisterImpl::Width w = is_double ? FloatRegisterImpl::D : FloatRegisterImpl::S;
- FloatRegister rsrc = op->in_opr()->as_float_reg();
- if (rsrc != rdst) {
- __ fmov(FloatRegisterImpl::S, rsrc, rdst);
- }
- __ fitof(w, rdst, rdst);
- break;
- }
- case Bytecodes::_f2i:{
- FloatRegister rsrc = op->in_opr()->as_float_reg();
- Address addr = frame_map()->address_for_slot(dst->single_stack_ix());
- Label L;
- // result must be 0 if value is NaN; test by comparing value to itself
- __ fcmp(FloatRegisterImpl::S, Assembler::fcc0, rsrc, rsrc);
- __ fb(Assembler::f_unordered, true, Assembler::pn, L);
- __ delayed()->st(G0, addr); // annuled if contents of rsrc is not NaN
- __ ftoi(FloatRegisterImpl::S, rsrc, rsrc);
- // move integer result from float register to int register
- __ stf(FloatRegisterImpl::S, rsrc, addr.base(), addr.disp());
- __ bind (L);
- break;
- }
- case Bytecodes::_l2i: {
- Register rlo = op->in_opr()->as_register_lo();
- Register rhi = op->in_opr()->as_register_hi();
- Register rdst = dst->as_register();
- __ sra(rlo, 0, rdst);
- break;
- }
- case Bytecodes::_d2f:
- case Bytecodes::_f2d: {
- bool is_double = (code == Bytecodes::_f2d);
- assert((!is_double && dst->is_single_fpu()) || (is_double && dst->is_double_fpu()), "check");
- LIR_Opr val = op->in_opr();
- FloatRegister rval = (code == Bytecodes::_d2f) ? val->as_double_reg() : val->as_float_reg();
- FloatRegister rdst = is_double ? dst->as_double_reg() : dst->as_float_reg();
- FloatRegisterImpl::Width vw = is_double ? FloatRegisterImpl::S : FloatRegisterImpl::D;
- FloatRegisterImpl::Width dw = is_double ? FloatRegisterImpl::D : FloatRegisterImpl::S;
- __ ftof(vw, dw, rval, rdst);
- break;
- }
- case Bytecodes::_i2s:
- case Bytecodes::_i2b: {
- Register rval = op->in_opr()->as_register();
- Register rdst = dst->as_register();
- int shift = (code == Bytecodes::_i2b) ? (BitsPerInt - T_BYTE_aelem_bytes * BitsPerByte) : (BitsPerInt - BitsPerShort);
- __ sll (rval, shift, rdst);
- __ sra (rdst, shift, rdst);
- break;
- }
- case Bytecodes::_i2c: {
- Register rval = op->in_opr()->as_register();
- Register rdst = dst->as_register();
- int shift = BitsPerInt - T_CHAR_aelem_bytes * BitsPerByte;
- __ sll (rval, shift, rdst);
- __ srl (rdst, shift, rdst);
- break;
- }
-
- default: ShouldNotReachHere();
- }
-}
-
-
-void LIR_Assembler::align_call(LIR_Code) {
- // do nothing since all instructions are word aligned on sparc
-}
-
-
-void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
- __ call(op->addr(), rtype);
- // The peephole pass fills the delay slot, add_call_info is done in
- // LIR_Assembler::emit_delay.
-}
-
-
-void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
- __ ic_call(op->addr(), false);
- // The peephole pass fills the delay slot, add_call_info is done in
- // LIR_Assembler::emit_delay.
-}
-
-
-void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
- add_debug_info_for_null_check_here(op->info());
- __ load_klass(O0, G3_scratch);
- if (Assembler::is_simm13(op->vtable_offset())) {
- __ ld_ptr(G3_scratch, op->vtable_offset(), G5_method);
- } else {
- // This will generate 2 instructions
- __ set(op->vtable_offset(), G5_method);
- // ld_ptr, set_hi, set
- __ ld_ptr(G3_scratch, G5_method, G5_method);
- }
- __ ld_ptr(G5_method, Method::from_compiled_offset(), G3_scratch);
- __ callr(G3_scratch, G0);
- // the peephole pass fills the delay slot
-}
-
-int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) {
- int store_offset;
- if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) {
- assert(base != O7, "destroying register");
- assert(!unaligned, "can't handle this");
- // for offsets larger than a simm13 we setup the offset in O7
- __ set(offset, O7);
- store_offset = store(from_reg, base, O7, type, wide);
- } else {
- if (is_reference_type(type)) {
- __ verify_oop(from_reg->as_register());
- }
- store_offset = code_offset();
- switch (type) {
- case T_BOOLEAN: // fall through
- case T_BYTE : __ stb(from_reg->as_register(), base, offset); break;
- case T_CHAR : __ sth(from_reg->as_register(), base, offset); break;
- case T_SHORT : __ sth(from_reg->as_register(), base, offset); break;
- case T_INT : __ stw(from_reg->as_register(), base, offset); break;
- case T_LONG :
- if (unaligned || PatchALot) {
- // Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem)
- assert(G3_scratch != base, "can't handle this");
- assert(G3_scratch != from_reg->as_register_lo(), "can't handle this");
- __ srax(from_reg->as_register_lo(), 32, G3_scratch);
- __ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes);
- __ stw(G3_scratch, base, offset + hi_word_offset_in_bytes);
- } else {
- __ stx(from_reg->as_register_lo(), base, offset);
- }
- break;
- case T_ADDRESS:
- case T_METADATA:
- __ st_ptr(from_reg->as_register(), base, offset);
- break;
- case T_ARRAY : // fall through
- case T_OBJECT:
- {
- if (UseCompressedOops && !wide) {
- __ encode_heap_oop(from_reg->as_register(), G3_scratch);
- store_offset = code_offset();
- __ stw(G3_scratch, base, offset);
- } else {
- __ st_ptr(from_reg->as_register(), base, offset);
- }
- break;
- }
-
- case T_FLOAT : __ stf(FloatRegisterImpl::S, from_reg->as_float_reg(), base, offset); break;
- case T_DOUBLE:
- {
- FloatRegister reg = from_reg->as_double_reg();
- // split unaligned stores
- if (unaligned || PatchALot) {
- assert(Assembler::is_simm13(offset + 4), "must be");
- __ stf(FloatRegisterImpl::S, reg->successor(), base, offset + 4);
- __ stf(FloatRegisterImpl::S, reg, base, offset);
- } else {
- __ stf(FloatRegisterImpl::D, reg, base, offset);
- }
- break;
- }
- default : ShouldNotReachHere();
- }
- }
- return store_offset;
-}
-
-
-int LIR_Assembler::store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide) {
- if (is_reference_type(type)) {
- __ verify_oop(from_reg->as_register());
- }
- int store_offset = code_offset();
- switch (type) {
- case T_BOOLEAN: // fall through
- case T_BYTE : __ stb(from_reg->as_register(), base, disp); break;
- case T_CHAR : __ sth(from_reg->as_register(), base, disp); break;
- case T_SHORT : __ sth(from_reg->as_register(), base, disp); break;
- case T_INT : __ stw(from_reg->as_register(), base, disp); break;
- case T_LONG :
- __ stx(from_reg->as_register_lo(), base, disp);
- break;
- case T_ADDRESS:
- __ st_ptr(from_reg->as_register(), base, disp);
- break;
- case T_ARRAY : // fall through
- case T_OBJECT:
- {
- if (UseCompressedOops && !wide) {
- __ encode_heap_oop(from_reg->as_register(), G3_scratch);
- store_offset = code_offset();
- __ stw(G3_scratch, base, disp);
- } else {
- __ st_ptr(from_reg->as_register(), base, disp);
- }
- break;
- }
- case T_FLOAT : __ stf(FloatRegisterImpl::S, from_reg->as_float_reg(), base, disp); break;
- case T_DOUBLE: __ stf(FloatRegisterImpl::D, from_reg->as_double_reg(), base, disp); break;
- default : ShouldNotReachHere();
- }
- return store_offset;
-}
-
-
-int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned) {
- int load_offset;
- if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) {
- assert(base != O7, "destroying register");
- assert(!unaligned, "can't handle this");
- // for offsets larger than a simm13 we setup the offset in O7
- __ set(offset, O7);
- load_offset = load(base, O7, to_reg, type, wide);
- } else {
- load_offset = code_offset();
- switch(type) {
- case T_BOOLEAN: // fall through
- case T_BYTE : __ ldsb(base, offset, to_reg->as_register()); break;
- case T_CHAR : __ lduh(base, offset, to_reg->as_register()); break;
- case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break;
- case T_INT : __ ld(base, offset, to_reg->as_register()); break;
- case T_LONG :
- if (!unaligned && !PatchALot) {
- __ ldx(base, offset, to_reg->as_register_lo());
- } else {
- assert(base != to_reg->as_register_lo(), "can't handle this");
- assert(O7 != to_reg->as_register_lo(), "can't handle this");
- __ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_lo());
- __ lduw(base, offset + lo_word_offset_in_bytes, O7); // in case O7 is base or offset, use it last
- __ sllx(to_reg->as_register_lo(), 32, to_reg->as_register_lo());
- __ or3(to_reg->as_register_lo(), O7, to_reg->as_register_lo());
- }
- break;
- case T_METADATA: __ ld_ptr(base, offset, to_reg->as_register()); break;
- case T_ADDRESS:
- if (offset == oopDesc::klass_offset_in_bytes() && UseCompressedClassPointers) {
- __ lduw(base, offset, to_reg->as_register());
- __ decode_klass_not_null(to_reg->as_register());
- } else
- {
- __ ld_ptr(base, offset, to_reg->as_register());
- }
- break;
- case T_ARRAY : // fall through
- case T_OBJECT:
- {
- if (UseCompressedOops && !wide) {
- __ lduw(base, offset, to_reg->as_register());
- __ decode_heap_oop(to_reg->as_register());
- } else {
- __ ld_ptr(base, offset, to_reg->as_register());
- }
- break;
- }
- case T_FLOAT: __ ldf(FloatRegisterImpl::S, base, offset, to_reg->as_float_reg()); break;
- case T_DOUBLE:
- {
- FloatRegister reg = to_reg->as_double_reg();
- // split unaligned loads
- if (unaligned || PatchALot) {
- __ ldf(FloatRegisterImpl::S, base, offset + 4, reg->successor());
- __ ldf(FloatRegisterImpl::S, base, offset, reg);
- } else {
- __ ldf(FloatRegisterImpl::D, base, offset, to_reg->as_double_reg());
- }
- break;
- }
- default : ShouldNotReachHere();
- }
- if (is_reference_type(type)) {
- __ verify_oop(to_reg->as_register());
- }
- }
- return load_offset;
-}
-
-
-int LIR_Assembler::load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide) {
- int load_offset = code_offset();
- switch(type) {
- case T_BOOLEAN: // fall through
- case T_BYTE : __ ldsb(base, disp, to_reg->as_register()); break;
- case T_CHAR : __ lduh(base, disp, to_reg->as_register()); break;
- case T_SHORT : __ ldsh(base, disp, to_reg->as_register()); break;
- case T_INT : __ ld(base, disp, to_reg->as_register()); break;
- case T_ADDRESS: __ ld_ptr(base, disp, to_reg->as_register()); break;
- case T_ARRAY : // fall through
- case T_OBJECT:
- {
- if (UseCompressedOops && !wide) {
- __ lduw(base, disp, to_reg->as_register());
- __ decode_heap_oop(to_reg->as_register());
- } else {
- __ ld_ptr(base, disp, to_reg->as_register());
- }
- break;
- }
- case T_FLOAT: __ ldf(FloatRegisterImpl::S, base, disp, to_reg->as_float_reg()); break;
- case T_DOUBLE: __ ldf(FloatRegisterImpl::D, base, disp, to_reg->as_double_reg()); break;
- case T_LONG :
- __ ldx(base, disp, to_reg->as_register_lo());
- break;
- default : ShouldNotReachHere();
- }
- if (is_reference_type(type)) {
- __ verify_oop(to_reg->as_register());
- }
- return load_offset;
-}
-
-void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) {
- LIR_Const* c = src->as_constant_ptr();
- switch (c->type()) {
- case T_INT:
- case T_FLOAT: {
- Register src_reg = O7;
- int value = c->as_jint_bits();
- if (value == 0) {
- src_reg = G0;
- } else {
- __ set(value, O7);
- }
- Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
- __ stw(src_reg, addr.base(), addr.disp());
- break;
- }
- case T_ADDRESS: {
- Register src_reg = O7;
- int value = c->as_jint_bits();
- if (value == 0) {
- src_reg = G0;
- } else {
- __ set(value, O7);
- }
- Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
- __ st_ptr(src_reg, addr.base(), addr.disp());
- break;
- }
- case T_OBJECT: {
- Register src_reg = O7;
- jobject2reg(c->as_jobject(), src_reg);
- Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
- __ st_ptr(src_reg, addr.base(), addr.disp());
- break;
- }
- case T_LONG:
- case T_DOUBLE: {
- Address addr = frame_map()->address_for_double_slot(dest->double_stack_ix());
-
- Register tmp = O7;
- int value_lo = c->as_jint_lo_bits();
- if (value_lo == 0) {
- tmp = G0;
- } else {
- __ set(value_lo, O7);
- }
- __ stw(tmp, addr.base(), addr.disp() + lo_word_offset_in_bytes);
- int value_hi = c->as_jint_hi_bits();
- if (value_hi == 0) {
- tmp = G0;
- } else {
- __ set(value_hi, O7);
- }
- __ stw(tmp, addr.base(), addr.disp() + hi_word_offset_in_bytes);
- break;
- }
- default:
- Unimplemented();
- }
-}
-
-
-void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) {
- LIR_Const* c = src->as_constant_ptr();
- LIR_Address* addr = dest->as_address_ptr();
- Register base = addr->base()->as_pointer_register();
- int offset = -1;
-
- switch (c->type()) {
- case T_FLOAT: type = T_INT; // Float constants are stored by int store instructions.
- case T_INT:
- case T_ADDRESS: {
- LIR_Opr tmp = FrameMap::O7_opr;
- int value = c->as_jint_bits();
- if (value == 0) {
- tmp = FrameMap::G0_opr;
- } else if (Assembler::is_simm13(value)) {
- __ set(value, O7);
- }
- if (addr->index()->is_valid()) {
- assert(addr->disp() == 0, "must be zero");
- offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide);
- } else {
- assert(Assembler::is_simm13(addr->disp()), "can't handle larger addresses");
- offset = store(tmp, base, addr->disp(), type, wide, false);
- }
- break;
- }
- case T_LONG:
- case T_DOUBLE: {
- assert(!addr->index()->is_valid(), "can't handle reg reg address here");
- assert(Assembler::is_simm13(addr->disp()) &&
- Assembler::is_simm13(addr->disp() + 4), "can't handle larger addresses");
-
- LIR_Opr tmp = FrameMap::O7_opr;
- int value_lo = c->as_jint_lo_bits();
- if (value_lo == 0) {
- tmp = FrameMap::G0_opr;
- } else {
- __ set(value_lo, O7);
- }
- offset = store(tmp, base, addr->disp() + lo_word_offset_in_bytes, T_INT, wide, false);
- int value_hi = c->as_jint_hi_bits();
- if (value_hi == 0) {
- tmp = FrameMap::G0_opr;
- } else {
- __ set(value_hi, O7);
- }
- store(tmp, base, addr->disp() + hi_word_offset_in_bytes, T_INT, wide, false);
- break;
- }
- case T_OBJECT: {
- jobject obj = c->as_jobject();
- LIR_Opr tmp;
- if (obj == NULL) {
- tmp = FrameMap::G0_opr;
- } else {
- tmp = FrameMap::O7_opr;
- jobject2reg(c->as_jobject(), O7);
- }
- // handle either reg+reg or reg+disp address
- if (addr->index()->is_valid()) {
- assert(addr->disp() == 0, "must be zero");
- offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide);
- } else {
- assert(Assembler::is_simm13(addr->disp()), "can't handle larger addresses");
- offset = store(tmp, base, addr->disp(), type, wide, false);
- }
-
- break;
- }
- default:
- Unimplemented();
- }
- if (info != NULL) {
- assert(offset != -1, "offset should've been set");
- add_debug_info_for_null_check(offset, info);
- }
-}
-
-
-void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) {
- LIR_Const* c = src->as_constant_ptr();
- LIR_Opr to_reg = dest;
-
- switch (c->type()) {
- case T_INT:
- case T_ADDRESS:
- {
- jint con = c->as_jint();
- if (to_reg->is_single_cpu()) {
- assert(patch_code == lir_patch_none, "no patching handled here");
- __ set(con, to_reg->as_register());
- } else {
- ShouldNotReachHere();
- assert(to_reg->is_single_fpu(), "wrong register kind");
-
- __ set(con, O7);
- Address temp_slot(SP, (frame::register_save_words * wordSize) + STACK_BIAS);
- __ st(O7, temp_slot);
- __ ldf(FloatRegisterImpl::S, temp_slot, to_reg->as_float_reg());
- }
- }
- break;
-
- case T_LONG:
- {
- jlong con = c->as_jlong();
-
- if (to_reg->is_double_cpu()) {
- __ set(con, to_reg->as_register_lo());
- } else if (to_reg->is_single_cpu()) {
- __ set(con, to_reg->as_register());
- } else {
- ShouldNotReachHere();
- assert(to_reg->is_double_fpu(), "wrong register kind");
- Address temp_slot_lo(SP, ((frame::register_save_words ) * wordSize) + STACK_BIAS);
- Address temp_slot_hi(SP, ((frame::register_save_words) * wordSize) + (longSize/2) + STACK_BIAS);
- __ set(low(con), O7);
- __ st(O7, temp_slot_lo);
- __ set(high(con), O7);
- __ st(O7, temp_slot_hi);
- __ ldf(FloatRegisterImpl::D, temp_slot_lo, to_reg->as_double_reg());
- }
- }
- break;
-
- case T_OBJECT:
- {
- if (patch_code == lir_patch_none) {
- jobject2reg(c->as_jobject(), to_reg->as_register());
- } else {
- jobject2reg_with_patching(to_reg->as_register(), info);
- }
- }
- break;
-
- case T_METADATA:
- {
- if (patch_code == lir_patch_none) {
- metadata2reg(c->as_metadata(), to_reg->as_register());
- } else {
- klass2reg_with_patching(to_reg->as_register(), info);
- }
- }
- break;
-
- case T_FLOAT:
- {
- address const_addr = __ float_constant(c->as_jfloat());
- if (const_addr == NULL) {
- bailout("const section overflow");
- break;
- }
- RelocationHolder rspec = internal_word_Relocation::spec(const_addr);
- AddressLiteral const_addrlit(const_addr, rspec);
- if (to_reg->is_single_fpu()) {
- __ patchable_sethi(const_addrlit, O7);
- __ relocate(rspec);
- __ ldf(FloatRegisterImpl::S, O7, const_addrlit.low10(), to_reg->as_float_reg());
-
- } else {
- assert(to_reg->is_single_cpu(), "Must be a cpu register.");
-
- __ set(const_addrlit, O7);
- __ ld(O7, 0, to_reg->as_register());
- }
- }
- break;
-
- case T_DOUBLE:
- {
- address const_addr = __ double_constant(c->as_jdouble());
- if (const_addr == NULL) {
- bailout("const section overflow");
- break;
- }
- RelocationHolder rspec = internal_word_Relocation::spec(const_addr);
-
- if (to_reg->is_double_fpu()) {
- AddressLiteral const_addrlit(const_addr, rspec);
- __ patchable_sethi(const_addrlit, O7);
- __ relocate(rspec);
- __ ldf (FloatRegisterImpl::D, O7, const_addrlit.low10(), to_reg->as_double_reg());
- } else {
- assert(to_reg->is_double_cpu(), "Must be a long register.");
- __ set(jlong_cast(c->as_jdouble()), to_reg->as_register_lo());
- }
-
- }
- break;
-
- default:
- ShouldNotReachHere();
- }
-}
-
-Address LIR_Assembler::as_Address(LIR_Address* addr) {
- Register reg = addr->base()->as_pointer_register();
- LIR_Opr index = addr->index();
- if (index->is_illegal()) {
- return Address(reg, addr->disp());
- } else {
- assert (addr->disp() == 0, "unsupported address mode");
- return Address(reg, index->as_pointer_register());
- }
-}
-
-
-void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) {
- switch (type) {
- case T_INT:
- case T_FLOAT: {
- Register tmp = O7;
- Address from = frame_map()->address_for_slot(src->single_stack_ix());
- Address to = frame_map()->address_for_slot(dest->single_stack_ix());
- __ lduw(from.base(), from.disp(), tmp);
- __ stw(tmp, to.base(), to.disp());
- break;
- }
- case T_ADDRESS:
- case T_OBJECT: {
- Register tmp = O7;
- Address from = frame_map()->address_for_slot(src->single_stack_ix());
- Address to = frame_map()->address_for_slot(dest->single_stack_ix());
- __ ld_ptr(from.base(), from.disp(), tmp);
- __ st_ptr(tmp, to.base(), to.disp());
- break;
- }
- case T_LONG:
- case T_DOUBLE: {
- Register tmp = O7;
- Address from = frame_map()->address_for_double_slot(src->double_stack_ix());
- Address to = frame_map()->address_for_double_slot(dest->double_stack_ix());
- __ lduw(from.base(), from.disp(), tmp);
- __ stw(tmp, to.base(), to.disp());
- __ lduw(from.base(), from.disp() + 4, tmp);
- __ stw(tmp, to.base(), to.disp() + 4);
- break;
- }
-
- default:
- ShouldNotReachHere();
- }
-}
-
-
-Address LIR_Assembler::as_Address_hi(LIR_Address* addr) {
- Address base = as_Address(addr);
- return Address(base.base(), base.disp() + hi_word_offset_in_bytes);
-}
-
-
-Address LIR_Assembler::as_Address_lo(LIR_Address* addr) {
- Address base = as_Address(addr);
- return Address(base.base(), base.disp() + lo_word_offset_in_bytes);
-}
-
-
-void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type,
- LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide, bool unaligned) {
-
- assert(type != T_METADATA, "load of metadata ptr not supported");
- LIR_Address* addr = src_opr->as_address_ptr();
- LIR_Opr to_reg = dest;
-
- Register src = addr->base()->as_pointer_register();
- Register disp_reg = noreg;
- int disp_value = addr->disp();
- bool needs_patching = (patch_code != lir_patch_none);
-
- if (addr->base()->type() == T_OBJECT) {
- __ verify_oop(src);
- }
-
- PatchingStub* patch = NULL;
- if (needs_patching) {
- patch = new PatchingStub(_masm, PatchingStub::access_field_id);
- assert(!to_reg->is_double_cpu() ||
- patch_code == lir_patch_none ||
- patch_code == lir_patch_normal, "patching doesn't match register");
- }
-
- if (addr->index()->is_illegal()) {
- if (!Assembler::is_simm13(disp_value) && (!unaligned || Assembler::is_simm13(disp_value + 4))) {
- if (needs_patching) {
- __ patchable_set(0, O7);
- } else {
- __ set(disp_value, O7);
- }
- disp_reg = O7;
- }
- } else if (unaligned || PatchALot) {
- __ add(src, addr->index()->as_pointer_register(), O7);
- src = O7;
- } else {
- disp_reg = addr->index()->as_pointer_register();
- assert(disp_value == 0, "can't handle 3 operand addresses");
- }
-
- // remember the offset of the load. The patching_epilog must be done
- // before the call to add_debug_info, otherwise the PcDescs don't get
- // entered in increasing order.
- int offset = code_offset();
-
- assert(disp_reg != noreg || Assembler::is_simm13(disp_value), "should have set this up");
- if (disp_reg == noreg) {
- offset = load(src, disp_value, to_reg, type, wide, unaligned);
- } else {
- assert(!unaligned, "can't handle this");
- offset = load(src, disp_reg, to_reg, type, wide);
- }
-
- if (patch != NULL) {
- patching_epilog(patch, patch_code, src, info);
- }
- if (info != NULL) add_debug_info_for_null_check(offset, info);
-}
-
-
-void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) {
- Address addr;
- if (src->is_single_word()) {
- addr = frame_map()->address_for_slot(src->single_stack_ix());
- } else if (src->is_double_word()) {
- addr = frame_map()->address_for_double_slot(src->double_stack_ix());
- }
-
- bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0;
- load(addr.base(), addr.disp(), dest, dest->type(), true /*wide*/, unaligned);
-}
-
-
-void LIR_Assembler::reg2stack(LIR_Opr from_reg, LIR_Opr dest, BasicType type, bool pop_fpu_stack) {
- Address addr;
- if (dest->is_single_word()) {
- addr = frame_map()->address_for_slot(dest->single_stack_ix());
- } else if (dest->is_double_word()) {
- addr = frame_map()->address_for_slot(dest->double_stack_ix());
- }
- bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0;
- store(from_reg, addr.base(), addr.disp(), from_reg->type(), true /*wide*/, unaligned);
-}
-
-
-void LIR_Assembler::reg2reg(LIR_Opr from_reg, LIR_Opr to_reg) {
- if (from_reg->is_float_kind() && to_reg->is_float_kind()) {
- if (from_reg->is_double_fpu()) {
- // double to double moves
- assert(to_reg->is_double_fpu(), "should match");
- __ fmov(FloatRegisterImpl::D, from_reg->as_double_reg(), to_reg->as_double_reg());
- } else {
- // float to float moves
- assert(to_reg->is_single_fpu(), "should match");
- __ fmov(FloatRegisterImpl::S, from_reg->as_float_reg(), to_reg->as_float_reg());
- }
- } else if (!from_reg->is_float_kind() && !to_reg->is_float_kind()) {
- if (from_reg->is_double_cpu()) {
- __ mov(from_reg->as_pointer_register(), to_reg->as_pointer_register());
- } else if (to_reg->is_double_cpu()) {
- // int to int moves
- __ mov(from_reg->as_register(), to_reg->as_register_lo());
- } else {
- // int to int moves
- __ mov(from_reg->as_register(), to_reg->as_register());
- }
- } else {
- ShouldNotReachHere();
- }
- if (is_reference_type(to_reg->type())) {
- __ verify_oop(to_reg->as_register());
- }
-}
-
-void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type,
- LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack,
- bool wide, bool unaligned) {
- assert(type != T_METADATA, "store of metadata ptr not supported");
- LIR_Address* addr = dest->as_address_ptr();
-
- Register src = addr->base()->as_pointer_register();
- Register disp_reg = noreg;
- int disp_value = addr->disp();
- bool needs_patching = (patch_code != lir_patch_none);
-
- if (addr->base()->is_oop_register()) {
- __ verify_oop(src);
- }
-
- PatchingStub* patch = NULL;
- if (needs_patching) {
- patch = new PatchingStub(_masm, PatchingStub::access_field_id);
- assert(!from_reg->is_double_cpu() ||
- patch_code == lir_patch_none ||
- patch_code == lir_patch_normal, "patching doesn't match register");
- }
-
- if (addr->index()->is_illegal()) {
- if (!Assembler::is_simm13(disp_value) && (!unaligned || Assembler::is_simm13(disp_value + 4))) {
- if (needs_patching) {
- __ patchable_set(0, O7);
- } else {
- __ set(disp_value, O7);
- }
- disp_reg = O7;
- }
- } else if (unaligned || PatchALot) {
- __ add(src, addr->index()->as_pointer_register(), O7);
- src = O7;
- } else {
- disp_reg = addr->index()->as_pointer_register();
- assert(disp_value == 0, "can't handle 3 operand addresses");
- }
-
- // remember the offset of the store. The patching_epilog must be done
- // before the call to add_debug_info_for_null_check, otherwise the PcDescs don't get
- // entered in increasing order.
- int offset;
-
- assert(disp_reg != noreg || Assembler::is_simm13(disp_value), "should have set this up");
- if (disp_reg == noreg) {
- offset = store(from_reg, src, disp_value, type, wide, unaligned);
- } else {
- assert(!unaligned, "can't handle this");
- offset = store(from_reg, src, disp_reg, type, wide);
- }
-
- if (patch != NULL) {
- patching_epilog(patch, patch_code, src, info);
- }
-
- if (info != NULL) add_debug_info_for_null_check(offset, info);
-}
-
-
-void LIR_Assembler::return_op(LIR_Opr result) {
- if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
- __ reserved_stack_check();
- }
- __ ld_ptr(Address(G2_thread, Thread::polling_page_offset()), L0);
- __ relocate(relocInfo::poll_return_type);
- __ ld_ptr(L0, 0, G0);
- __ ret();
- __ delayed()->restore();
-}
-
-
-int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
- __ ld_ptr(Address(G2_thread, Thread::polling_page_offset()), tmp->as_register());
- if (info != NULL) {
- add_debug_info_for_branch(info);
- }
- int offset = __ offset();
-
- __ relocate(relocInfo::poll_type);
- __ ld_ptr(tmp->as_register(), 0, G0);
- return offset;
-}
-
-
-void LIR_Assembler::emit_static_call_stub() {
- address call_pc = __ pc();
- address stub = __ start_a_stub(call_stub_size());
- if (stub == NULL) {
- bailout("static call stub overflow");
- return;
- }
-
- int start = __ offset();
- __ relocate(static_stub_Relocation::spec(call_pc));
-
- __ set_metadata(NULL, G5);
- // must be set to -1 at code generation time
- AddressLiteral addrlit(-1);
- __ jump_to(addrlit, G3);
- __ delayed()->nop();
-
- assert(__ offset() - start <= call_stub_size(), "stub too big");
- __ end_a_stub();
-}
-
-
-void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) {
- if (opr1->is_single_fpu()) {
- __ fcmp(FloatRegisterImpl::S, Assembler::fcc0, opr1->as_float_reg(), opr2->as_float_reg());
- } else if (opr1->is_double_fpu()) {
- __ fcmp(FloatRegisterImpl::D, Assembler::fcc0, opr1->as_double_reg(), opr2->as_double_reg());
- } else if (opr1->is_single_cpu()) {
- if (opr2->is_constant()) {
- switch (opr2->as_constant_ptr()->type()) {
- case T_INT:
- { jint con = opr2->as_constant_ptr()->as_jint();
- if (Assembler::is_simm13(con)) {
- __ cmp(opr1->as_register(), con);
- } else {
- __ set(con, O7);
- __ cmp(opr1->as_register(), O7);
- }
- }
- break;
-
- case T_OBJECT:
- // there are only equal/notequal comparisions on objects
- { jobject con = opr2->as_constant_ptr()->as_jobject();
- if (con == NULL) {
- __ cmp(opr1->as_register(), 0);
- } else {
- jobject2reg(con, O7);
- __ cmp(opr1->as_register(), O7);
- }
- }
- break;
-
- case T_METADATA:
- // We only need, for now, comparison with NULL for metadata.
- { assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops");
- Metadata* m = opr2->as_constant_ptr()->as_metadata();
- if (m == NULL) {
- __ cmp(opr1->as_register(), 0);
- } else {
- ShouldNotReachHere();
- }
- }
- break;
-
- default:
- ShouldNotReachHere();
- break;
- }
- } else {
- if (opr2->is_address()) {
- LIR_Address * addr = opr2->as_address_ptr();
- BasicType type = addr->type();
- if ( type == T_OBJECT ) __ ld_ptr(as_Address(addr), O7);
- else __ ld(as_Address(addr), O7);
- __ cmp(opr1->as_register(), O7);
- } else {
- __ cmp(opr1->as_register(), opr2->as_register());
- }
- }
- } else if (opr1->is_double_cpu()) {
- Register xlo = opr1->as_register_lo();
- Register xhi = opr1->as_register_hi();
- if (opr2->is_constant() && opr2->as_jlong() == 0) {
- assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "only handles these cases");
- __ orcc(xhi, G0, G0);
- } else if (opr2->is_register()) {
- Register ylo = opr2->as_register_lo();
- Register yhi = opr2->as_register_hi();
- __ cmp(xlo, ylo);
- } else {
- ShouldNotReachHere();
- }
- } else if (opr1->is_address()) {
- LIR_Address * addr = opr1->as_address_ptr();
- BasicType type = addr->type();
- assert (opr2->is_constant(), "Checking");
- if ( type == T_OBJECT ) __ ld_ptr(as_Address(addr), O7);
- else __ ld(as_Address(addr), O7);
- __ cmp(O7, opr2->as_constant_ptr()->as_jint());
- } else {
- ShouldNotReachHere();
- }
-}
-
-
-void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op){
- if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) {
- bool is_unordered_less = (code == lir_ucmp_fd2i);
- if (left->is_single_fpu()) {
- __ float_cmp(true, is_unordered_less ? -1 : 1, left->as_float_reg(), right->as_float_reg(), dst->as_register());
- } else if (left->is_double_fpu()) {
- __ float_cmp(false, is_unordered_less ? -1 : 1, left->as_double_reg(), right->as_double_reg(), dst->as_register());
- } else {
- ShouldNotReachHere();
- }
- } else if (code == lir_cmp_l2i) {
- __ lcmp(left->as_register_lo(), right->as_register_lo(), dst->as_register());
- } else {
- ShouldNotReachHere();
- }
-}
-
-
-void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) {
- Assembler::Condition acond;
- switch (condition) {
- case lir_cond_equal: acond = Assembler::equal; break;
- case lir_cond_notEqual: acond = Assembler::notEqual; break;
- case lir_cond_less: acond = Assembler::less; break;
- case lir_cond_lessEqual: acond = Assembler::lessEqual; break;
- case lir_cond_greaterEqual: acond = Assembler::greaterEqual; break;
- case lir_cond_greater: acond = Assembler::greater; break;
- case lir_cond_aboveEqual: acond = Assembler::greaterEqualUnsigned; break;
- case lir_cond_belowEqual: acond = Assembler::lessEqualUnsigned; break;
- default: ShouldNotReachHere();
- };
-
- if (opr1->is_constant() && opr1->type() == T_INT) {
- Register dest = result->as_register();
- // load up first part of constant before branch
- // and do the rest in the delay slot.
- if (!Assembler::is_simm13(opr1->as_jint())) {
- __ sethi(opr1->as_jint(), dest);
- }
- } else if (opr1->is_constant()) {
- const2reg(opr1, result, lir_patch_none, NULL);
- } else if (opr1->is_register()) {
- reg2reg(opr1, result);
- } else if (opr1->is_stack()) {
- stack2reg(opr1, result, result->type());
- } else {
- ShouldNotReachHere();
- }
- Label skip;
- if (type == T_INT) {
- __ br(acond, false, Assembler::pt, skip);
- } else {
- __ brx(acond, false, Assembler::pt, skip); // checks icc on 32bit and xcc on 64bit
- }
- if (opr1->is_constant() && opr1->type() == T_INT) {
- Register dest = result->as_register();
- if (Assembler::is_simm13(opr1->as_jint())) {
- __ delayed()->or3(G0, opr1->as_jint(), dest);
- } else {
- // the sethi has been done above, so just put in the low 10 bits
- __ delayed()->or3(dest, opr1->as_jint() & 0x3ff, dest);
- }
- } else {
- // can't do anything useful in the delay slot
- __ delayed()->nop();
- }
- if (opr2->is_constant()) {
- const2reg(opr2, result, lir_patch_none, NULL);
- } else if (opr2->is_register()) {
- reg2reg(opr2, result);
- } else if (opr2->is_stack()) {
- stack2reg(opr2, result, result->type());
- } else {
- ShouldNotReachHere();
- }
- __ bind(skip);
-}
-
-
-void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack) {
- assert(info == NULL, "unused on this code path");
- assert(left->is_register(), "wrong items state");
- assert(dest->is_register(), "wrong items state");
-
- if (right->is_register()) {
- if (dest->is_float_kind()) {
-
- FloatRegister lreg, rreg, res;
- FloatRegisterImpl::Width w;
- if (right->is_single_fpu()) {
- w = FloatRegisterImpl::S;
- lreg = left->as_float_reg();
- rreg = right->as_float_reg();
- res = dest->as_float_reg();
- } else {
- w = FloatRegisterImpl::D;
- lreg = left->as_double_reg();
- rreg = right->as_double_reg();
- res = dest->as_double_reg();
- }
-
- switch (code) {
- case lir_add: __ fadd(w, lreg, rreg, res); break;
- case lir_sub: __ fsub(w, lreg, rreg, res); break;
- case lir_mul: // fall through
- case lir_mul_strictfp: __ fmul(w, lreg, rreg, res); break;
- case lir_div: // fall through
- case lir_div_strictfp: __ fdiv(w, lreg, rreg, res); break;
- default: ShouldNotReachHere();
- }
-
- } else if (dest->is_double_cpu()) {
- Register dst_lo = dest->as_register_lo();
- Register op1_lo = left->as_pointer_register();
- Register op2_lo = right->as_pointer_register();
-
- switch (code) {
- case lir_add:
- __ add(op1_lo, op2_lo, dst_lo);
- break;
-
- case lir_sub:
- __ sub(op1_lo, op2_lo, dst_lo);
- break;
-
- default: ShouldNotReachHere();
- }
- } else {
- assert (right->is_single_cpu(), "Just Checking");
-
- Register lreg = left->as_register();
- Register res = dest->as_register();
- Register rreg = right->as_register();
- switch (code) {
- case lir_add: __ add (lreg, rreg, res); break;
- case lir_sub: __ sub (lreg, rreg, res); break;
- case lir_mul: __ mulx (lreg, rreg, res); break;
- default: ShouldNotReachHere();
- }
- }
- } else {
- assert (right->is_constant(), "must be constant");
-
- if (dest->is_single_cpu()) {
- Register lreg = left->as_register();
- Register res = dest->as_register();
- int simm13 = right->as_constant_ptr()->as_jint();
-
- switch (code) {
- case lir_add: __ add (lreg, simm13, res); break;
- case lir_sub: __ sub (lreg, simm13, res); break;
- case lir_mul: __ mulx (lreg, simm13, res); break;
- default: ShouldNotReachHere();
- }
- } else {
- Register lreg = left->as_pointer_register();
- Register res = dest->as_register_lo();
- long con = right->as_constant_ptr()->as_jlong();
- assert(Assembler::is_simm13(con), "must be simm13");
-
- switch (code) {
- case lir_add: __ add (lreg, (int)con, res); break;
- case lir_sub: __ sub (lreg, (int)con, res); break;
- case lir_mul: __ mulx (lreg, (int)con, res); break;
- default: ShouldNotReachHere();
- }
- }
- }
-}
-
-void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr thread, LIR_Opr dest, LIR_Op* op) {
- switch (code) {
- case lir_tan: {
- assert(thread->is_valid(), "preserve the thread object for performance reasons");
- assert(dest->as_double_reg() == F0, "the result will be in f0/f1");
- break;
- }
- case lir_sqrt: {
- assert(!thread->is_valid(), "there is no need for a thread_reg for dsqrt");
- FloatRegister src_reg = value->as_double_reg();
- FloatRegister dst_reg = dest->as_double_reg();
- __ fsqrt(FloatRegisterImpl::D, src_reg, dst_reg);
- break;
- }
- case lir_abs: {
- assert(!thread->is_valid(), "there is no need for a thread_reg for fabs");
- FloatRegister src_reg = value->as_double_reg();
- FloatRegister dst_reg = dest->as_double_reg();
- __ fabs(FloatRegisterImpl::D, src_reg, dst_reg);
- break;
- }
- default: {
- ShouldNotReachHere();
- break;
- }
- }
-}
-
-
-void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
- if (right->is_constant()) {
- if (dest->is_single_cpu()) {
- int simm13 = right->as_constant_ptr()->as_jint();
- switch (code) {
- case lir_logic_and: __ and3 (left->as_register(), simm13, dest->as_register()); break;
- case lir_logic_or: __ or3 (left->as_register(), simm13, dest->as_register()); break;
- case lir_logic_xor: __ xor3 (left->as_register(), simm13, dest->as_register()); break;
- default: ShouldNotReachHere();
- }
- } else {
- long c = right->as_constant_ptr()->as_jlong();
- assert(c == (int)c && Assembler::is_simm13(c), "out of range");
- int simm13 = (int)c;
- switch (code) {
- case lir_logic_and:
- __ and3 (left->as_register_lo(), simm13, dest->as_register_lo());
- break;
-
- case lir_logic_or:
- __ or3 (left->as_register_lo(), simm13, dest->as_register_lo());
- break;
-
- case lir_logic_xor:
- __ xor3 (left->as_register_lo(), simm13, dest->as_register_lo());
- break;
-
- default: ShouldNotReachHere();
- }
- }
- } else {
- assert(right->is_register(), "right should be in register");
-
- if (dest->is_single_cpu()) {
- switch (code) {
- case lir_logic_and: __ and3 (left->as_register(), right->as_register(), dest->as_register()); break;
- case lir_logic_or: __ or3 (left->as_register(), right->as_register(), dest->as_register()); break;
- case lir_logic_xor: __ xor3 (left->as_register(), right->as_register(), dest->as_register()); break;
- default: ShouldNotReachHere();
- }
- } else {
- Register l = (left->is_single_cpu() && left->is_oop_register()) ? left->as_register() :
- left->as_register_lo();
- Register r = (right->is_single_cpu() && right->is_oop_register()) ? right->as_register() :
- right->as_register_lo();
-
- switch (code) {
- case lir_logic_and: __ and3 (l, r, dest->as_register_lo()); break;
- case lir_logic_or: __ or3 (l, r, dest->as_register_lo()); break;
- case lir_logic_xor: __ xor3 (l, r, dest->as_register_lo()); break;
- default: ShouldNotReachHere();
- }
- }
- }
-}
-
-
-int LIR_Assembler::shift_amount(BasicType t) {
- int elem_size = type2aelembytes(t);
- switch (elem_size) {
- case 1 : return 0;
- case 2 : return 1;
- case 4 : return 2;
- case 8 : return 3;
- }
- ShouldNotReachHere();
- return -1;
-}
-
-
-void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
- assert(exceptionOop->as_register() == Oexception, "should match");
- assert(exceptionPC->as_register() == Oissuing_pc, "should match");
-
- info->add_register_oop(exceptionOop);
-
- // reuse the debug info from the safepoint poll for the throw op itself
- address pc_for_athrow = __ pc();
- int pc_for_athrow_offset = __ offset();
- RelocationHolder rspec = internal_word_Relocation::spec(pc_for_athrow);
- __ set(pc_for_athrow, Oissuing_pc, rspec);
- add_call_info(pc_for_athrow_offset, info); // for exception handler
-
- __ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
-}
-
-
-void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) {
- assert(exceptionOop->as_register() == Oexception, "should match");
-
- __ br(Assembler::always, false, Assembler::pt, _unwind_handler_entry);
- __ delayed()->nop();
-}
-
-void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
- Register src = op->src()->as_register();
- Register dst = op->dst()->as_register();
- Register src_pos = op->src_pos()->as_register();
- Register dst_pos = op->dst_pos()->as_register();
- Register length = op->length()->as_register();
- Register tmp = op->tmp()->as_register();
- Register tmp2 = O7;
-
- int flags = op->flags();
- ciArrayKlass* default_type = op->expected_type();
- BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
- if (basic_type == T_ARRAY) basic_type = T_OBJECT;
-
- // higher 32bits must be null
- __ sra(dst_pos, 0, dst_pos);
- __ sra(src_pos, 0, src_pos);
- __ sra(length, 0, length);
-
- // set up the arraycopy stub information
- ArrayCopyStub* stub = op->stub();
-
- // always do stub if no type information is available. it's ok if
- // the known type isn't loaded since the code sanity checks
- // in debug mode and the type isn't required when we know the exact type
- // also check that the type is an array type.
- if (op->expected_type() == NULL) {
- __ mov(src, O0);
- __ mov(src_pos, O1);
- __ mov(dst, O2);
- __ mov(dst_pos, O3);
- __ mov(length, O4);
- address copyfunc_addr = StubRoutines::generic_arraycopy();
- assert(copyfunc_addr != NULL, "generic arraycopy stub required");
-
-#ifndef PRODUCT
- if (PrintC1Statistics) {
- address counter = (address)&Runtime1::_generic_arraycopystub_cnt;
- __ inc_counter(counter, G1, G3);
- }
-#endif
- __ call_VM_leaf(tmp, copyfunc_addr);
-
- __ xor3(O0, -1, tmp);
- __ sub(length, tmp, length);
- __ add(src_pos, tmp, src_pos);
- __ cmp_zero_and_br(Assembler::less, O0, *stub->entry());
- __ delayed()->add(dst_pos, tmp, dst_pos);
- __ bind(*stub->continuation());
- return;
- }
-
- assert(default_type != NULL && default_type->is_array_klass(), "must be true at this point");
-
- // make sure src and dst are non-null and load array length
- if (flags & LIR_OpArrayCopy::src_null_check) {
- __ tst(src);
- __ brx(Assembler::equal, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- }
-
- if (flags & LIR_OpArrayCopy::dst_null_check) {
- __ tst(dst);
- __ brx(Assembler::equal, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- }
-
- // If the compiler was not able to prove that exact type of the source or the destination
- // of the arraycopy is an array type, check at runtime if the source or the destination is
- // an instance type.
- if (flags & LIR_OpArrayCopy::type_check) {
- if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::dst_objarray)) {
- __ load_klass(dst, tmp);
- __ lduw(tmp, in_bytes(Klass::layout_helper_offset()), tmp2);
- __ cmp(tmp2, Klass::_lh_neutral_value);
- __ br(Assembler::greaterEqual, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- }
-
- if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) {
- __ load_klass(src, tmp);
- __ lduw(tmp, in_bytes(Klass::layout_helper_offset()), tmp2);
- __ cmp(tmp2, Klass::_lh_neutral_value);
- __ br(Assembler::greaterEqual, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- }
- }
-
- if (flags & LIR_OpArrayCopy::src_pos_positive_check) {
- // test src_pos register
- __ cmp_zero_and_br(Assembler::less, src_pos, *stub->entry());
- __ delayed()->nop();
- }
-
- if (flags & LIR_OpArrayCopy::dst_pos_positive_check) {
- // test dst_pos register
- __ cmp_zero_and_br(Assembler::less, dst_pos, *stub->entry());
- __ delayed()->nop();
- }
-
- if (flags & LIR_OpArrayCopy::length_positive_check) {
- // make sure length isn't negative
- __ cmp_zero_and_br(Assembler::less, length, *stub->entry());
- __ delayed()->nop();
- }
-
- if (flags & LIR_OpArrayCopy::src_range_check) {
- __ ld(src, arrayOopDesc::length_offset_in_bytes(), tmp2);
- __ add(length, src_pos, tmp);
- __ cmp(tmp2, tmp);
- __ br(Assembler::carrySet, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- }
-
- if (flags & LIR_OpArrayCopy::dst_range_check) {
- __ ld(dst, arrayOopDesc::length_offset_in_bytes(), tmp2);
- __ add(length, dst_pos, tmp);
- __ cmp(tmp2, tmp);
- __ br(Assembler::carrySet, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- }
-
- int shift = shift_amount(basic_type);
-
- if (flags & LIR_OpArrayCopy::type_check) {
- // We don't know the array types are compatible
- if (basic_type != T_OBJECT) {
- // Simple test for basic type arrays
- if (UseCompressedClassPointers) {
- // We don't need decode because we just need to compare
- __ lduw(src, oopDesc::klass_offset_in_bytes(), tmp);
- __ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2);
- __ cmp(tmp, tmp2);
- __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry());
- } else {
- __ ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp);
- __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2);
- __ cmp(tmp, tmp2);
- __ brx(Assembler::notEqual, false, Assembler::pt, *stub->entry());
- }
- __ delayed()->nop();
- } else {
- // For object arrays, if src is a sub class of dst then we can
- // safely do the copy.
- address copyfunc_addr = StubRoutines::checkcast_arraycopy();
-
- Label cont, slow;
- assert_different_registers(tmp, tmp2, G3, G1);
-
- __ load_klass(src, G3);
- __ load_klass(dst, G1);
-
- __ check_klass_subtype_fast_path(G3, G1, tmp, tmp2, &cont, copyfunc_addr == NULL ? stub->entry() : &slow, NULL);
-
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
-
- __ cmp(G3, 0);
- if (copyfunc_addr != NULL) { // use stub if available
- // src is not a sub class of dst so we have to do a
- // per-element check.
- __ br(Assembler::notEqual, false, Assembler::pt, cont);
- __ delayed()->nop();
-
- __ bind(slow);
-
- int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray;
- if ((flags & mask) != mask) {
- // Check that at least both of them object arrays.
- assert(flags & mask, "one of the two should be known to be an object array");
-
- if (!(flags & LIR_OpArrayCopy::src_objarray)) {
- __ load_klass(src, tmp);
- } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) {
- __ load_klass(dst, tmp);
- }
- int lh_offset = in_bytes(Klass::layout_helper_offset());
-
- __ lduw(tmp, lh_offset, tmp2);
-
- jint objArray_lh = Klass::array_layout_helper(T_OBJECT);
- __ set(objArray_lh, tmp);
- __ cmp(tmp, tmp2);
- __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry());
- __ delayed()->nop();
- }
-
- Register src_ptr = O0;
- Register dst_ptr = O1;
- Register len = O2;
- Register chk_off = O3;
- Register super_k = O4;
-
- __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr);
- if (shift == 0) {
- __ add(src_ptr, src_pos, src_ptr);
- } else {
- __ sll(src_pos, shift, tmp);
- __ add(src_ptr, tmp, src_ptr);
- }
-
- __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr);
- if (shift == 0) {
- __ add(dst_ptr, dst_pos, dst_ptr);
- } else {
- __ sll(dst_pos, shift, tmp);
- __ add(dst_ptr, tmp, dst_ptr);
- }
- __ mov(length, len);
- __ load_klass(dst, tmp);
-
- int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
- __ ld_ptr(tmp, ek_offset, super_k);
-
- int sco_offset = in_bytes(Klass::super_check_offset_offset());
- __ lduw(super_k, sco_offset, chk_off);
-
- __ call_VM_leaf(tmp, copyfunc_addr);
-
-#ifndef PRODUCT
- if (PrintC1Statistics) {
- Label failed;
- __ br_notnull_short(O0, Assembler::pn, failed);
- __ inc_counter((address)&Runtime1::_arraycopy_checkcast_cnt, G1, G3);
- __ bind(failed);
- }
-#endif
-
- __ br_null(O0, false, Assembler::pt, *stub->continuation());
- __ delayed()->xor3(O0, -1, tmp);
-
-#ifndef PRODUCT
- if (PrintC1Statistics) {
- __ inc_counter((address)&Runtime1::_arraycopy_checkcast_attempt_cnt, G1, G3);
- }
-#endif
-
- __ sub(length, tmp, length);
- __ add(src_pos, tmp, src_pos);
- __ br(Assembler::always, false, Assembler::pt, *stub->entry());
- __ delayed()->add(dst_pos, tmp, dst_pos);
-
- __ bind(cont);
- } else {
- __ br(Assembler::equal, false, Assembler::pn, *stub->entry());
- __ delayed()->nop();
- __ bind(cont);
- }
- }
- }
-
-#ifdef ASSERT
- if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) {
- // Sanity check the known type with the incoming class. For the
- // primitive case the types must match exactly with src.klass and
- // dst.klass each exactly matching the default type. For the
- // object array case, if no type check is needed then either the
- // dst type is exactly the expected type and the src type is a
- // subtype which we can't check or src is the same array as dst
- // but not necessarily exactly of type default_type.
- Label known_ok, halt;
- metadata2reg(op->expected_type()->constant_encoding(), tmp);
- if (UseCompressedClassPointers) {
- // tmp holds the default type. It currently comes uncompressed after the
- // load of a constant, so encode it.
- __ encode_klass_not_null(tmp);
- // load the raw value of the dst klass, since we will be comparing
- // uncompressed values directly.
- __ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2);
- if (basic_type != T_OBJECT) {
- __ cmp(tmp, tmp2);
- __ br(Assembler::notEqual, false, Assembler::pn, halt);
- // load the raw value of the src klass.
- __ delayed()->lduw(src, oopDesc::klass_offset_in_bytes(), tmp2);
- __ cmp_and_br_short(tmp, tmp2, Assembler::equal, Assembler::pn, known_ok);
- } else {
- __ cmp(tmp, tmp2);
- __ br(Assembler::equal, false, Assembler::pn, known_ok);
- __ delayed()->cmp(src, dst);
- __ brx(Assembler::equal, false, Assembler::pn, known_ok);
- __ delayed()->nop();
- }
- } else {
- __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2);
- if (basic_type != T_OBJECT) {
- __ cmp(tmp, tmp2);
- __ brx(Assembler::notEqual, false, Assembler::pn, halt);
- __ delayed()->ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp2);
- __ cmp_and_brx_short(tmp, tmp2, Assembler::equal, Assembler::pn, known_ok);
- } else {
- __ cmp(tmp, tmp2);
- __ brx(Assembler::equal, false, Assembler::pn, known_ok);
- __ delayed()->cmp(src, dst);
- __ brx(Assembler::equal, false, Assembler::pn, known_ok);
- __ delayed()->nop();
- }
- }
- __ bind(halt);
- __ stop("incorrect type information in arraycopy");
- __ bind(known_ok);
- }
-#endif
-
-#ifndef PRODUCT
- if (PrintC1Statistics) {
- address counter = Runtime1::arraycopy_count_address(basic_type);
- __ inc_counter(counter, G1, G3);
- }
-#endif
-
- Register src_ptr = O0;
- Register dst_ptr = O1;
- Register len = O2;
-
- __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr);
- if (shift == 0) {
- __ add(src_ptr, src_pos, src_ptr);
- } else {
- __ sll(src_pos, shift, tmp);
- __ add(src_ptr, tmp, src_ptr);
- }
-
- __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr);
- if (shift == 0) {
- __ add(dst_ptr, dst_pos, dst_ptr);
- } else {
- __ sll(dst_pos, shift, tmp);
- __ add(dst_ptr, tmp, dst_ptr);
- }
-
- bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0;
- bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0;
- const char *name;
- address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false);
-
- // arraycopy stubs takes a length in number of elements, so don't scale it.
- __ mov(length, len);
- __ call_VM_leaf(tmp, entry);
-
- __ bind(*stub->continuation());
-}
-
-
-void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) {
- if (dest->is_single_cpu()) {
- if (left->type() == T_OBJECT) {
- switch (code) {
- case lir_shl: __ sllx (left->as_register(), count->as_register(), dest->as_register()); break;
- case lir_shr: __ srax (left->as_register(), count->as_register(), dest->as_register()); break;
- case lir_ushr: __ srl (left->as_register(), count->as_register(), dest->as_register()); break;
- default: ShouldNotReachHere();
- }
- } else
- switch (code) {
- case lir_shl: __ sll (left->as_register(), count->as_register(), dest->as_register()); break;
- case lir_shr: __ sra (left->as_register(), count->as_register(), dest->as_register()); break;
- case lir_ushr: __ srl (left->as_register(), count->as_register(), dest->as_register()); break;
- default: ShouldNotReachHere();
- }
- } else {
- switch (code) {
- case lir_shl: __ sllx (left->as_register_lo(), count->as_register(), dest->as_register_lo()); break;
- case lir_shr: __ srax (left->as_register_lo(), count->as_register(), dest->as_register_lo()); break;
- case lir_ushr: __ srlx (left->as_register_lo(), count->as_register(), dest->as_register_lo()); break;
- default: ShouldNotReachHere();
- }
- }
-}
-
-
-void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) {
- if (left->type() == T_OBJECT) {
- count = count & 63; // shouldn't shift by more than sizeof(intptr_t)
- Register l = left->as_register();
- Register d = dest->as_register_lo();
- switch (code) {
- case lir_shl: __ sllx (l, count, d); break;
- case lir_shr: __ srax (l, count, d); break;
- case lir_ushr: __ srlx (l, count, d); break;
- default: ShouldNotReachHere();
- }
- return;
- }
-
- if (dest->is_single_cpu()) {
- count = count & 0x1F; // Java spec
- switch (code) {
- case lir_shl: __ sll (left->as_register(), count, dest->as_register()); break;
- case lir_shr: __ sra (left->as_register(), count, dest->as_register()); break;
- case lir_ushr: __ srl (left->as_register(), count, dest->as_register()); break;
- default: ShouldNotReachHere();
- }
- } else if (dest->is_double_cpu()) {
- count = count & 63; // Java spec
- switch (code) {
- case lir_shl: __ sllx (left->as_pointer_register(), count, dest->as_pointer_register()); break;
- case lir_shr: __ srax (left->as_pointer_register(), count, dest->as_pointer_register()); break;
- case lir_ushr: __ srlx (left->as_pointer_register(), count, dest->as_pointer_register()); break;
- default: ShouldNotReachHere();
- }
- } else {
- ShouldNotReachHere();
- }
-}
-
-
-void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) {
- assert(op->tmp1()->as_register() == G1 &&
- op->tmp2()->as_register() == G3 &&
- op->tmp3()->as_register() == G4 &&
- op->obj()->as_register() == O0 &&
- op->klass()->as_register() == G5, "must be");
- if (op->init_check()) {
- add_debug_info_for_null_check_here(op->stub()->info());
- __ ldub(op->klass()->as_register(),
- in_bytes(InstanceKlass::init_state_offset()),
- op->tmp1()->as_register());
- __ cmp(op->tmp1()->as_register(), InstanceKlass::fully_initialized);
- __ br(Assembler::notEqual, false, Assembler::pn, *op->stub()->entry());
- __ delayed()->nop();
- }
- __ allocate_object(op->obj()->as_register(),
- op->tmp1()->as_register(),
- op->tmp2()->as_register(),
- op->tmp3()->as_register(),
- op->header_size(),
- op->object_size(),
- op->klass()->as_register(),
- *op->stub()->entry());
- __ bind(*op->stub()->continuation());
- __ verify_oop(op->obj()->as_register());
-}
-
-
-void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
- assert(op->tmp1()->as_register() == G1 &&
- op->tmp2()->as_register() == G3 &&
- op->tmp3()->as_register() == G4 &&
- op->tmp4()->as_register() == O1 &&
- op->klass()->as_register() == G5, "must be");
-
- __ signx(op->len()->as_register());
- if (UseSlowPath ||
- (!UseFastNewObjectArray && is_reference_type(op->type())) ||
- (!UseFastNewTypeArray && !is_reference_type(op->type()))) {
- __ br(Assembler::always, false, Assembler::pt, *op->stub()->entry());
- __ delayed()->nop();
- } else {
- __ allocate_array(op->obj()->as_register(),
- op->len()->as_register(),
- op->tmp1()->as_register(),
- op->tmp2()->as_register(),
- op->tmp3()->as_register(),
- arrayOopDesc::header_size(op->type()),
- type2aelembytes(op->type()),
- op->klass()->as_register(),
- *op->stub()->entry());
- }
- __ bind(*op->stub()->continuation());
-}
-
-
-void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias,
- ciMethodData *md, ciProfileData *data,
- Register recv, Register tmp1, Label* update_done) {
- uint i;
- for (i = 0; i < VirtualCallData::row_limit(); i++) {
- Label next_test;
- // See if the receiver is receiver[n].
- Address receiver_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) -
- mdo_offset_bias);
- __ ld_ptr(receiver_addr, tmp1);
- __ verify_klass_ptr(tmp1);
- __ cmp_and_brx_short(recv, tmp1, Assembler::notEqual, Assembler::pt, next_test);
- Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) -
- mdo_offset_bias);
- __ ld_ptr(data_addr, tmp1);
- __ add(tmp1, DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, data_addr);
- __ ba(*update_done);
- __ delayed()->nop();
- __ bind(next_test);
- }
-
- // Didn't find receiver; find next empty slot and fill it in
- for (i = 0; i < VirtualCallData::row_limit(); i++) {
- Label next_test;
- Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) -
- mdo_offset_bias);
- __ ld_ptr(recv_addr, tmp1);
- __ br_notnull_short(tmp1, Assembler::pt, next_test);
- __ st_ptr(recv, recv_addr);
- __ set(DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) -
- mdo_offset_bias);
- __ ba(*update_done);
- __ delayed()->nop();
- __ bind(next_test);
- }
-}
-
-
-void LIR_Assembler::setup_md_access(ciMethod* method, int bci,
- ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) {
- md = method->method_data_or_null();
- assert(md != NULL, "Sanity");
- data = md->bci_to_data(bci);
- assert(data != NULL, "need data for checkcast");
- assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check");
- if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) {
- // The offset is large so bias the mdo by the base of the slot so
- // that the ld can use simm13s to reference the slots of the data
- mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset());
- }
-}
-
-void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) {
- // we always need a stub for the failure case.
- CodeStub* stub = op->stub();
- Register obj = op->object()->as_register();
- Register k_RInfo = op->tmp1()->as_register();
- Register klass_RInfo = op->tmp2()->as_register();
- Register dst = op->result_opr()->as_register();
- Register Rtmp1 = op->tmp3()->as_register();
- ciKlass* k = op->klass();
-
-
- if (obj == k_RInfo) {
- k_RInfo = klass_RInfo;
- klass_RInfo = obj;
- }
-
- ciMethodData* md;
- ciProfileData* data;
- int mdo_offset_bias = 0;
- if (op->should_profile()) {
- ciMethod* method = op->profiled_method();
- assert(method != NULL, "Should have method");
- setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias);
-
- Label not_null;
- __ br_notnull_short(obj, Assembler::pn, not_null);
- Register mdo = k_RInfo;
- Register data_val = Rtmp1;
- metadata2reg(md->constant_encoding(), mdo);
- if (mdo_offset_bias > 0) {
- __ set(mdo_offset_bias, data_val);
- __ add(mdo, data_val, mdo);
- }
- Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias);
- __ ldub(flags_addr, data_val);
- __ or3(data_val, BitData::null_seen_byte_constant(), data_val);
- __ stb(data_val, flags_addr);
- __ ba(*obj_is_null);
- __ delayed()->nop();
- __ bind(not_null);
- } else {
- __ br_null(obj, false, Assembler::pn, *obj_is_null);
- __ delayed()->nop();
- }
-
- Label 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;
-
- // patching may screw with our temporaries on sparc,
- // so let's do it before loading the class
- if (k->is_loaded()) {
- metadata2reg(k->constant_encoding(), k_RInfo);
- } else {
- klass2reg_with_patching(k_RInfo, op->info_for_patch());
- }
- assert(obj != k_RInfo, "must be different");
-
- // get object class
- // not a safepoint as obj null check happens earlier
- __ load_klass(obj, klass_RInfo);
- if (op->fast_check()) {
- assert_different_registers(klass_RInfo, k_RInfo);
- __ cmp(k_RInfo, klass_RInfo);
- __ brx(Assembler::notEqual, false, Assembler::pt, *failure_target);
- __ delayed()->nop();
- } else {
- bool need_slow_path = true;
- if (k->is_loaded()) {
- if ((int) k->super_check_offset() != in_bytes(Klass::secondary_super_cache_offset()))
- need_slow_path = false;
- // perform the fast part of the checking logic
- __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg,
- (need_slow_path ? success_target : NULL),
- failure_target, NULL,
- RegisterOrConstant(k->super_check_offset()));
- } else {
- // perform the fast part of the checking logic
- __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target,
- failure_target, NULL);
- }
- if (need_slow_path) {
- // call out-of-line instance of __ check_klass_subtype_slow_path(...):
- assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- __ cmp(G3, 0);
- __ br(Assembler::equal, false, Assembler::pn, *failure_target);
- __ delayed()->nop();
- // Fall through to success case
- }
- }
-
- if (op->should_profile()) {
- Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1;
- assert_different_registers(obj, mdo, recv, tmp1);
- __ bind(profile_cast_success);
- metadata2reg(md->constant_encoding(), mdo);
- if (mdo_offset_bias > 0) {
- __ set(mdo_offset_bias, tmp1);
- __ add(mdo, tmp1, mdo);
- }
- __ load_klass(obj, recv);
- type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, success);
- // Jump over the failure case
- __ ba(*success);
- __ delayed()->nop();
- // Cast failure case
- __ bind(profile_cast_failure);
- metadata2reg(md->constant_encoding(), mdo);
- if (mdo_offset_bias > 0) {
- __ set(mdo_offset_bias, tmp1);
- __ add(mdo, tmp1, mdo);
- }
- Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias);
- __ ld_ptr(data_addr, tmp1);
- __ sub(tmp1, DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, data_addr);
- __ ba(*failure);
- __ delayed()->nop();
- }
- __ ba(*success);
- __ delayed()->nop();
-}
-
-void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
- LIR_Code code = op->code();
- if (code == lir_store_check) {
- Register value = op->object()->as_register();
- Register array = op->array()->as_register();
- Register k_RInfo = op->tmp1()->as_register();
- Register klass_RInfo = op->tmp2()->as_register();
- Register Rtmp1 = op->tmp3()->as_register();
-
- __ verify_oop(value);
- CodeStub* stub = op->stub();
- // check if it needs to be profiled
- ciMethodData* md;
- ciProfileData* data;
- int mdo_offset_bias = 0;
- if (op->should_profile()) {
- ciMethod* method = op->profiled_method();
- assert(method != NULL, "Should have method");
- setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias);
- }
- Label 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();
-
- if (op->should_profile()) {
- Label not_null;
- __ br_notnull_short(value, Assembler::pn, not_null);
- Register mdo = k_RInfo;
- Register data_val = Rtmp1;
- metadata2reg(md->constant_encoding(), mdo);
- if (mdo_offset_bias > 0) {
- __ set(mdo_offset_bias, data_val);
- __ add(mdo, data_val, mdo);
- }
- Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias);
- __ ldub(flags_addr, data_val);
- __ or3(data_val, BitData::null_seen_byte_constant(), data_val);
- __ stb(data_val, flags_addr);
- __ ba_short(done);
- __ bind(not_null);
- } else {
- __ br_null_short(value, Assembler::pn, done);
- }
- add_debug_info_for_null_check_here(op->info_for_exception());
- __ load_klass(array, k_RInfo);
- __ load_klass(value, klass_RInfo);
-
- // get instance klass
- __ ld_ptr(Address(k_RInfo, ObjArrayKlass::element_klass_offset()), k_RInfo);
- // perform the fast part of the checking logic
- __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target, failure_target, NULL);
-
- // call out-of-line instance of __ check_klass_subtype_slow_path(...):
- assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup");
- __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
- __ delayed()->nop();
- __ cmp(G3, 0);
- __ br(Assembler::equal, false, Assembler::pn, *failure_target);
- __ delayed()->nop();
- // fall through to the success case
-
- if (op->should_profile()) {
- Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1;
- assert_different_registers(value, mdo, recv, tmp1);
- __ bind(profile_cast_success);
- metadata2reg(md->constant_encoding(), mdo);
- if (mdo_offset_bias > 0) {
- __ set(mdo_offset_bias, tmp1);
- __ add(mdo, tmp1, mdo);
- }
- __ load_klass(value, recv);
- type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &done);
- __ ba_short(done);
- // Cast failure case
- __ bind(profile_cast_failure);
- metadata2reg(md->constant_encoding(), mdo);
- if (mdo_offset_bias > 0) {
- __ set(mdo_offset_bias, tmp1);
- __ add(mdo, tmp1, mdo);
- }
- Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias);
- __ ld_ptr(data_addr, tmp1);
- __ sub(tmp1, DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, data_addr);
- __ ba(*stub->entry());
- __ delayed()->nop();
- }
- __ bind(done);
- } else if (code == lir_checkcast) {
- Register obj = op->object()->as_register();
- Register dst = op->result_opr()->as_register();
- Label success;
- emit_typecheck_helper(op, &success, op->stub()->entry(), &success);
- __ bind(success);
- __ mov(obj, dst);
- } else if (code == lir_instanceof) {
- Register obj = op->object()->as_register();
- Register dst = op->result_opr()->as_register();
- Label success, failure, done;
- emit_typecheck_helper(op, &success, &failure, &failure);
- __ bind(failure);
- __ set(0, dst);
- __ ba_short(done);
- __ bind(success);
- __ set(1, dst);
- __ bind(done);
- } else {
- ShouldNotReachHere();
- }
-
-}
-
-
-void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
- if (op->code() == lir_cas_long) {
- assert(VM_Version::supports_cx8(), "wrong machine");
- Register addr = op->addr()->as_pointer_register();
- Register cmp_value_lo = op->cmp_value()->as_register_lo();
- Register cmp_value_hi = op->cmp_value()->as_register_hi();
- Register new_value_lo = op->new_value()->as_register_lo();
- Register new_value_hi = op->new_value()->as_register_hi();
- Register t1 = op->tmp1()->as_register();
- Register t2 = op->tmp2()->as_register();
- __ mov(cmp_value_lo, t1);
- __ mov(new_value_lo, t2);
- // perform the compare and swap operation
- __ casx(addr, t1, t2);
- // generate condition code - if the swap succeeded, t2 ("new value" reg) was
- // overwritten with the original value in "addr" and will be equal to t1.
- __ cmp(t1, t2);
- } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj) {
- Register addr = op->addr()->as_pointer_register();
- Register cmp_value = op->cmp_value()->as_register();
- Register new_value = op->new_value()->as_register();
- Register t1 = op->tmp1()->as_register();
- Register t2 = op->tmp2()->as_register();
- __ mov(cmp_value, t1);
- __ mov(new_value, t2);
- if (op->code() == lir_cas_obj) {
- if (UseCompressedOops) {
- __ encode_heap_oop(t1);
- __ encode_heap_oop(t2);
- __ cas(addr, t1, t2);
- } else {
- __ cas_ptr(addr, t1, t2);
- }
- } else {
- __ cas(addr, t1, t2);
- }
- __ cmp(t1, t2);
- } else {
- Unimplemented();
- }
-}
-
-void LIR_Assembler::breakpoint() {
- __ breakpoint_trap();
-}
-
-
-void LIR_Assembler::push(LIR_Opr opr) {
- Unimplemented();
-}
-
-
-void LIR_Assembler::pop(LIR_Opr opr) {
- Unimplemented();
-}
-
-
-void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst_opr) {
- Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no);
- Register dst = dst_opr->as_register();
- Register reg = mon_addr.base();
- int offset = mon_addr.disp();
- // compute pointer to BasicLock
- if (mon_addr.is_simm13()) {
- __ add(reg, offset, dst);
- } else {
- __ set(offset, dst);
- __ add(dst, reg, dst);
- }
-}
-
-void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
- assert(op->crc()->is_single_cpu(), "crc must be register");
- assert(op->val()->is_single_cpu(), "byte value must be register");
- assert(op->result_opr()->is_single_cpu(), "result must be register");
- Register crc = op->crc()->as_register();
- Register val = op->val()->as_register();
- Register table = op->result_opr()->as_register();
- Register res = op->result_opr()->as_register();
-
- assert_different_registers(val, crc, table);
-
- __ set(ExternalAddress(StubRoutines::crc_table_addr()), table);
- __ not1(crc);
- __ clruwu(crc);
- __ update_byte_crc32(crc, val, table);
- __ not1(crc);
-
- __ mov(crc, res);
-}
-
-void LIR_Assembler::emit_lock(LIR_OpLock* op) {
- Register obj = op->obj_opr()->as_register();
- Register hdr = op->hdr_opr()->as_register();
- Register lock = op->lock_opr()->as_register();
-
- // obj may not be an oop
- if (op->code() == lir_lock) {
- MonitorEnterStub* stub = (MonitorEnterStub*)op->stub();
- if (UseFastLocking) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
- // add debug info for NullPointerException only if one is possible
- if (op->info() != NULL) {
- add_debug_info_for_null_check_here(op->info());
- }
- __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry());
- } else {
- // always do slow locking
- // note: the slow locking code could be inlined here, however if we use
- // slow locking, speed doesn't matter anyway and this solution is
- // simpler and requires less duplicated code - additionally, the
- // slow locking code is the same in either case which simplifies
- // debugging
- __ br(Assembler::always, false, Assembler::pt, *op->stub()->entry());
- __ delayed()->nop();
- }
- } else {
- assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock");
- if (UseFastLocking) {
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
- __ unlock_object(hdr, obj, lock, *op->stub()->entry());
- } else {
- // always do slow unlocking
- // note: the slow unlocking code could be inlined here, however if we use
- // slow unlocking, speed doesn't matter anyway and this solution is
- // simpler and requires less duplicated code - additionally, the
- // slow unlocking code is the same in either case which simplifies
- // debugging
- __ br(Assembler::always, false, Assembler::pt, *op->stub()->entry());
- __ delayed()->nop();
- }
- }
- __ bind(*op->stub()->continuation());
-}
-
-
-void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
- ciMethod* method = op->profiled_method();
- int bci = op->profiled_bci();
- ciMethod* callee = op->profiled_callee();
-
- // Update counter for all call types
- ciMethodData* md = method->method_data_or_null();
- assert(md != NULL, "Sanity");
- ciProfileData* data = md->bci_to_data(bci);
- assert(data != NULL && data->is_CounterData(), "need CounterData for calls");
- assert(op->mdo()->is_single_cpu(), "mdo must be allocated");
- Register mdo = op->mdo()->as_register();
- assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated");
- Register tmp1 = op->tmp1()->as_register_lo();
- metadata2reg(md->constant_encoding(), mdo);
- int mdo_offset_bias = 0;
- if (!Assembler::is_simm13(md->byte_offset_of_slot(data, CounterData::count_offset()) +
- data->size_in_bytes())) {
- // The offset is large so bias the mdo by the base of the slot so
- // that the ld can use simm13s to reference the slots of the data
- mdo_offset_bias = md->byte_offset_of_slot(data, CounterData::count_offset());
- __ set(mdo_offset_bias, O7);
- __ add(mdo, O7, mdo);
- }
-
- Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias);
- // Perform additional virtual call profiling for invokevirtual and
- // invokeinterface bytecodes
- if (op->should_profile_receiver_type()) {
- assert(op->recv()->is_single_cpu(), "recv must be allocated");
- Register recv = op->recv()->as_register();
- assert_different_registers(mdo, tmp1, recv);
- assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls");
- ciKlass* known_klass = op->known_holder();
- if (C1OptimizeVirtualCallProfiling && known_klass != NULL) {
- // We know the type that will be seen at this call site; we can
- // statically update the MethodData* rather than needing to do
- // dynamic tests on the receiver type
-
- // NOTE: we should probably put a lock around this search to
- // avoid collisions by concurrent compilations
- ciVirtualCallData* vc_data = (ciVirtualCallData*) data;
- uint i;
- for (i = 0; i < VirtualCallData::row_limit(); i++) {
- ciKlass* receiver = vc_data->receiver(i);
- if (known_klass->equals(receiver)) {
- Address data_addr(mdo, md->byte_offset_of_slot(data,
- VirtualCallData::receiver_count_offset(i)) -
- mdo_offset_bias);
- __ ld_ptr(data_addr, tmp1);
- __ add(tmp1, DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, data_addr);
- return;
- }
- }
-
- // Receiver type not found in profile data; select an empty slot
-
- // Note that this is less efficient than it should be because it
- // always does a write to the receiver part of the
- // VirtualCallData rather than just the first time
- for (i = 0; i < VirtualCallData::row_limit(); i++) {
- ciKlass* receiver = vc_data->receiver(i);
- if (receiver == NULL) {
- Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) -
- mdo_offset_bias);
- metadata2reg(known_klass->constant_encoding(), tmp1);
- __ st_ptr(tmp1, recv_addr);
- Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) -
- mdo_offset_bias);
- __ ld_ptr(data_addr, tmp1);
- __ add(tmp1, DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, data_addr);
- return;
- }
- }
- } else {
- __ load_klass(recv, recv);
- Label update_done;
- type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done);
- // Receiver did not match any saved receiver and there is no empty row for it.
- // Increment total counter to indicate polymorphic case.
- __ ld_ptr(counter_addr, tmp1);
- __ add(tmp1, DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, counter_addr);
-
- __ bind(update_done);
- }
- } else {
- // Static call
- __ ld_ptr(counter_addr, tmp1);
- __ add(tmp1, DataLayout::counter_increment, tmp1);
- __ st_ptr(tmp1, counter_addr);
- }
-}
-
-void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
- Register obj = op->obj()->as_register();
- Register tmp1 = op->tmp()->as_pointer_register();
- Register tmp2 = G1;
- Address mdo_addr = as_Address(op->mdp()->as_address_ptr());
- ciKlass* exact_klass = op->exact_klass();
- intptr_t current_klass = op->current_klass();
- bool not_null = op->not_null();
- bool no_conflict = op->no_conflict();
-
- Label update, next, none;
-
- bool do_null = !not_null;
- bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass;
- bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set;
-
- assert(do_null || do_update, "why are we here?");
- assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?");
-
- __ verify_oop(obj);
-
- if (tmp1 != obj) {
- __ mov(obj, tmp1);
- }
- if (do_null) {
- __ br_notnull_short(tmp1, Assembler::pt, update);
- if (!TypeEntries::was_null_seen(current_klass)) {
- __ ld_ptr(mdo_addr, tmp1);
- __ or3(tmp1, TypeEntries::null_seen, tmp1);
- __ st_ptr(tmp1, mdo_addr);
- }
- if (do_update) {
- __ ba(next);
- __ delayed()->nop();
- }
-#ifdef ASSERT
- } else {
- __ br_notnull_short(tmp1, Assembler::pt, update);
- __ stop("unexpect null obj");
-#endif
- }
-
- __ bind(update);
-
- if (do_update) {
-#ifdef ASSERT
- if (exact_klass != NULL) {
- Label ok;
- __ load_klass(tmp1, tmp1);
- metadata2reg(exact_klass->constant_encoding(), tmp2);
- __ cmp_and_br_short(tmp1, tmp2, Assembler::equal, Assembler::pt, ok);
- __ stop("exact klass and actual klass differ");
- __ bind(ok);
- }
-#endif
-
- Label do_update;
- __ ld_ptr(mdo_addr, tmp2);
-
- if (!no_conflict) {
- if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) {
- if (exact_klass != NULL) {
- metadata2reg(exact_klass->constant_encoding(), tmp1);
- } else {
- __ load_klass(tmp1, tmp1);
- }
-
- __ xor3(tmp1, tmp2, tmp1);
- __ btst(TypeEntries::type_klass_mask, tmp1);
- // klass seen before, nothing to do. The unknown bit may have been
- // set already but no need to check.
- __ brx(Assembler::zero, false, Assembler::pt, next);
- __ delayed()->
-
- btst(TypeEntries::type_unknown, tmp1);
- // already unknown. Nothing to do anymore.
- __ brx(Assembler::notZero, false, Assembler::pt, next);
-
- if (TypeEntries::is_type_none(current_klass)) {
- __ delayed()->btst(TypeEntries::type_mask, tmp2);
- __ brx(Assembler::zero, true, Assembler::pt, do_update);
- // first time here. Set profile type.
- __ delayed()->or3(tmp2, tmp1, tmp2);
- } else {
- __ delayed()->nop();
- }
- } else {
- assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
- ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only");
-
- __ btst(TypeEntries::type_unknown, tmp2);
- // already unknown. Nothing to do anymore.
- __ brx(Assembler::notZero, false, Assembler::pt, next);
- __ delayed()->nop();
- }
-
- // different than before. Cannot keep accurate profile.
- __ or3(tmp2, TypeEntries::type_unknown, tmp2);
- } else {
- // There's a single possible klass at this profile point
- assert(exact_klass != NULL, "should be");
- if (TypeEntries::is_type_none(current_klass)) {
- metadata2reg(exact_klass->constant_encoding(), tmp1);
- __ xor3(tmp1, tmp2, tmp1);
- __ btst(TypeEntries::type_klass_mask, tmp1);
- __ brx(Assembler::zero, false, Assembler::pt, next);
-#ifdef ASSERT
-
- {
- Label ok;
- __ delayed()->btst(TypeEntries::type_mask, tmp2);
- __ brx(Assembler::zero, true, Assembler::pt, ok);
- __ delayed()->nop();
-
- __ stop("unexpected profiling mismatch");
- __ bind(ok);
- }
- // first time here. Set profile type.
- __ or3(tmp2, tmp1, tmp2);
-#else
- // first time here. Set profile type.
- __ delayed()->or3(tmp2, tmp1, tmp2);
-#endif
-
- } else {
- assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
- ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");
-
- // already unknown. Nothing to do anymore.
- __ btst(TypeEntries::type_unknown, tmp2);
- __ brx(Assembler::notZero, false, Assembler::pt, next);
- __ delayed()->or3(tmp2, TypeEntries::type_unknown, tmp2);
- }
- }
-
- __ bind(do_update);
- __ st_ptr(tmp2, mdo_addr);
-
- __ bind(next);
- }
-}
-
-void LIR_Assembler::align_backward_branch_target() {
- __ align(OptoLoopAlignment);
-}
-
-
-void LIR_Assembler::emit_delay(LIR_OpDelay* op) {
- // make sure we are expecting a delay
- // this has the side effect of clearing the delay state
- // so we can use _masm instead of _masm->delayed() to do the
- // code generation.
- __ delayed();
-
- // make sure we only emit one instruction
- int offset = code_offset();
- op->delay_op()->emit_code(this);
-#ifdef ASSERT
- if (code_offset() - offset != NativeInstruction::nop_instruction_size) {
- op->delay_op()->print();
- }
- assert(code_offset() - offset == NativeInstruction::nop_instruction_size,
- "only one instruction can go in a delay slot");
-#endif
-
- // we may also be emitting the call info for the instruction
- // which we are the delay slot of.
- CodeEmitInfo* call_info = op->call_info();
- if (call_info) {
- add_call_info(code_offset(), call_info);
- }
-
- if (VerifyStackAtCalls) {
- _masm->sub(FP, SP, O7);
- _masm->cmp(O7, initial_frame_size_in_bytes());
- _masm->trap(Assembler::notEqual, Assembler::ptr_cc, G0, ST_RESERVED_FOR_USER_0+2 );
- }
-}
-
-
-void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
- // tmp must be unused
- assert(tmp->is_illegal(), "wasting a register if tmp is allocated");
- assert(left->is_register(), "can only handle registers");
-
- if (left->is_single_cpu()) {
- __ neg(left->as_register(), dest->as_register());
- } else if (left->is_single_fpu()) {
- __ fneg(FloatRegisterImpl::S, left->as_float_reg(), dest->as_float_reg());
- } else if (left->is_double_fpu()) {
- __ fneg(FloatRegisterImpl::D, left->as_double_reg(), dest->as_double_reg());
- } else {
- assert (left->is_double_cpu(), "Must be a long");
- Register Rlow = left->as_register_lo();
- Register Rhi = left->as_register_hi();
- __ sub(G0, Rlow, dest->as_register_lo());
- }
-}
-
-void LIR_Assembler::rt_call(LIR_Opr result, address dest,
- const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) {
-
- // if tmp is invalid, then the function being called doesn't destroy the thread
- if (tmp->is_valid()) {
- __ save_thread(tmp->as_pointer_register());
- }
- __ call(dest, relocInfo::runtime_call_type);
- __ delayed()->nop();
- if (info != NULL) {
- add_call_info_here(info);
- }
- if (tmp->is_valid()) {
- __ restore_thread(tmp->as_pointer_register());
- }
-
-#ifdef ASSERT
- __ verify_thread();
-#endif // ASSERT
-}
-
-
-void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) {
- ShouldNotReachHere();
-
- NEEDS_CLEANUP;
- if (type == T_LONG) {
- LIR_Address* mem_addr = dest->is_address() ? dest->as_address_ptr() : src->as_address_ptr();
-
- // (extended to allow indexed as well as constant displaced for JSR-166)
- Register idx = noreg; // contains either constant offset or index
-
- int disp = mem_addr->disp();
- if (mem_addr->index() == LIR_OprFact::illegalOpr) {
- if (!Assembler::is_simm13(disp)) {
- idx = O7;
- __ set(disp, idx);
- }
- } else {
- assert(disp == 0, "not both indexed and disp");
- idx = mem_addr->index()->as_register();
- }
-
- int null_check_offset = -1;
-
- Register base = mem_addr->base()->as_register();
- if (src->is_register() && dest->is_address()) {
- // G4 is high half, G5 is low half
- // clear the top bits of G5, and scale up G4
- __ srl (src->as_register_lo(), 0, G5);
- __ sllx(src->as_register_hi(), 32, G4);
- // combine the two halves into the 64 bits of G4
- __ or3(G4, G5, G4);
- null_check_offset = __ offset();
- if (idx == noreg) {
- __ stx(G4, base, disp);
- } else {
- __ stx(G4, base, idx);
- }
- } else if (src->is_address() && dest->is_register()) {
- null_check_offset = __ offset();
- if (idx == noreg) {
- __ ldx(base, disp, G5);
- } else {
- __ ldx(base, idx, G5);
- }
- __ srax(G5, 32, dest->as_register_hi()); // fetch the high half into hi
- __ mov (G5, dest->as_register_lo()); // copy low half into lo
- } else {
- Unimplemented();
- }
- if (info != NULL) {
- add_debug_info_for_null_check(null_check_offset, info);
- }
-
- } else {
- // use normal move for all other volatiles since they don't need
- // special handling to remain atomic.
- move_op(src, dest, type, lir_patch_none, info, false, false, false);
- }
-}
-
-void LIR_Assembler::membar() {
- // only StoreLoad membars are ever explicitly needed on sparcs in TSO mode
- __ membar( Assembler::Membar_mask_bits(Assembler::StoreLoad) );
-}
-
-void LIR_Assembler::membar_acquire() {
- // no-op on TSO
-}
-
-void LIR_Assembler::membar_release() {
- // no-op on TSO
-}
-
-void LIR_Assembler::membar_loadload() {
- // no-op
- //__ membar(Assembler::Membar_mask_bits(Assembler::loadload));
-}
-
-void LIR_Assembler::membar_storestore() {
- // no-op
- //__ membar(Assembler::Membar_mask_bits(Assembler::storestore));
-}
-
-void LIR_Assembler::membar_loadstore() {
- // no-op
- //__ membar(Assembler::Membar_mask_bits(Assembler::loadstore));
-}
-
-void LIR_Assembler::membar_storeload() {
- __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
-}
-
-void LIR_Assembler::on_spin_wait() {
- Unimplemented();
-}
-
-// Pack two sequential registers containing 32 bit values
-// into a single 64 bit register.
-// src and src->successor() are packed into dst
-// src and dst may be the same register.
-// Note: src is destroyed
-void LIR_Assembler::pack64(LIR_Opr src, LIR_Opr dst) {
- Register rs = src->as_register();
- Register rd = dst->as_register_lo();
- __ sllx(rs, 32, rs);
- __ srl(rs->successor(), 0, rs->successor());
- __ or3(rs, rs->successor(), rd);
-}
-
-// Unpack a 64 bit value in a register into
-// two sequential registers.
-// src is unpacked into dst and dst->successor()
-void LIR_Assembler::unpack64(LIR_Opr src, LIR_Opr dst) {
- Register rs = src->as_register_lo();
- Register rd = dst->as_register_hi();
- assert_different_registers(rs, rd, rd->successor());
- __ srlx(rs, 32, rd);
- __ srl (rs, 0, rd->successor());
-}
-
-void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) {
- const LIR_Address* addr = addr_opr->as_address_ptr();
- assert(addr->scale() == LIR_Address::times_1, "can't handle complex addresses yet");
- const Register dest_reg = dest->as_pointer_register();
- const Register base_reg = addr->base()->as_pointer_register();
-
- if (patch_code != lir_patch_none) {
- PatchingStub* patch = new PatchingStub(_masm, PatchingStub::access_field_id);
- assert(addr->disp() != 0, "must have");
- assert(base_reg != G3_scratch, "invariant");
- __ patchable_set(0, G3_scratch);
- patching_epilog(patch, patch_code, base_reg, info);
- assert(dest_reg != G3_scratch, "invariant");
- if (addr->index()->is_valid()) {
- const Register index_reg = addr->index()->as_pointer_register();
- assert(index_reg != G3_scratch, "invariant");
- __ add(index_reg, G3_scratch, G3_scratch);
- }
- __ add(base_reg, G3_scratch, dest_reg);
- } else {
- if (Assembler::is_simm13(addr->disp())) {
- if (addr->index()->is_valid()) {
- const Register index_reg = addr->index()->as_pointer_register();
- assert(index_reg != G3_scratch, "invariant");
- __ add(base_reg, addr->disp(), G3_scratch);
- __ add(index_reg, G3_scratch, dest_reg);
- } else {
- __ add(base_reg, addr->disp(), dest_reg);
- }
- } else {
- __ set(addr->disp(), G3_scratch);
- if (addr->index()->is_valid()) {
- const Register index_reg = addr->index()->as_pointer_register();
- assert(index_reg != G3_scratch, "invariant");
- __ add(index_reg, G3_scratch, G3_scratch);
- }
- __ add(base_reg, G3_scratch, dest_reg);
- }
- }
-}
-
-
-void LIR_Assembler::get_thread(LIR_Opr result_reg) {
- assert(result_reg->is_register(), "check");
- __ mov(G2_thread, result_reg->as_register());
-}
-
-#ifdef ASSERT
-// emit run-time assertion
-void LIR_Assembler::emit_assert(LIR_OpAssert* op) {
- assert(op->code() == lir_assert, "must be");
-
- if (op->in_opr1()->is_valid()) {
- assert(op->in_opr2()->is_valid(), "both operands must be valid");
- comp_op(op->condition(), op->in_opr1(), op->in_opr2(), op);
- } else {
- assert(op->in_opr2()->is_illegal(), "both operands must be illegal");
- assert(op->condition() == lir_cond_always, "no other conditions allowed");
- }
-
- Label ok;
- if (op->condition() != lir_cond_always) {
- Assembler::Condition acond;
- switch (op->condition()) {
- case lir_cond_equal: acond = Assembler::equal; break;
- case lir_cond_notEqual: acond = Assembler::notEqual; break;
- case lir_cond_less: acond = Assembler::less; break;
- case lir_cond_lessEqual: acond = Assembler::lessEqual; break;
- case lir_cond_greaterEqual: acond = Assembler::greaterEqual; break;
- case lir_cond_greater: acond = Assembler::greater; break;
- case lir_cond_aboveEqual: acond = Assembler::greaterEqualUnsigned; break;
- case lir_cond_belowEqual: acond = Assembler::lessEqualUnsigned; break;
- default: ShouldNotReachHere();
- };
- __ br(acond, false, Assembler::pt, ok);
- __ delayed()->nop();
- }
- if (op->halt()) {
- const char* str = __ code_string(op->msg());
- __ stop(str);
- } else {
- breakpoint();
- }
- __ bind(ok);
-}
-#endif
-
-void LIR_Assembler::peephole(LIR_List* lir) {
- LIR_OpList* inst = lir->instructions_list();
- for (int i = 0; i < inst->length(); i++) {
- LIR_Op* op = inst->at(i);
- switch (op->code()) {
- case lir_cond_float_branch:
- case lir_branch: {
- LIR_OpBranch* branch = op->as_OpBranch();
- assert(branch->info() == NULL, "shouldn't be state on branches anymore");
- LIR_Op* delay_op = NULL;
- // we'd like to be able to pull following instructions into
- // this slot but we don't know enough to do it safely yet so
- // only optimize block to block control flow.
- if (LIRFillDelaySlots && branch->block()) {
- LIR_Op* prev = inst->at(i - 1);
- if (prev && LIR_Assembler::is_single_instruction(prev) && prev->info() == NULL) {
- // swap previous instruction into delay slot
- inst->at_put(i - 1, op);
- inst->at_put(i, new LIR_OpDelay(prev, op->info()));
-#ifndef PRODUCT
- if (LIRTracePeephole) {
- tty->print_cr("delayed");
- inst->at(i - 1)->print();
- inst->at(i)->print();
- tty->cr();
- }
-#endif
- continue;
- }
- }
-
- if (!delay_op) {
- delay_op = new LIR_OpDelay(new LIR_Op0(lir_nop), NULL);
- }
- inst->insert_before(i + 1, delay_op);
- break;
- }
- case lir_static_call:
- case lir_virtual_call:
- case lir_icvirtual_call:
- case lir_optvirtual_call:
- case lir_dynamic_call: {
- LIR_Op* prev = inst->at(i - 1);
- if (LIRFillDelaySlots && prev && prev->code() == lir_move && prev->info() == NULL &&
- (op->code() != lir_virtual_call ||
- !prev->result_opr()->is_single_cpu() ||
- prev->result_opr()->as_register() != O0) &&
- LIR_Assembler::is_single_instruction(prev)) {
- // Only moves without info can be put into the delay slot.
- // Also don't allow the setup of the receiver in the delay
- // slot for vtable calls.
- inst->at_put(i - 1, op);
- inst->at_put(i, new LIR_OpDelay(prev, op->info()));
-#ifndef PRODUCT
- if (LIRTracePeephole) {
- tty->print_cr("delayed");
- inst->at(i - 1)->print();
- inst->at(i)->print();
- tty->cr();
- }
-#endif
- } else {
- LIR_Op* delay_op = new LIR_OpDelay(new LIR_Op0(lir_nop), op->as_OpJavaCall()->info());
- inst->insert_before(i + 1, delay_op);
- i++;
- }
- break;
- }
- }
- }
-}
-
-void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) {
- LIR_Address* addr = src->as_address_ptr();
-
- assert(data == dest, "swap uses only 2 operands");
- assert (code == lir_xchg, "no xadd on sparc");
-
- if (data->type() == T_INT) {
- __ swap(as_Address(addr), data->as_register());
- } else if (data->is_oop()) {
- Register obj = data->as_register();
- Register narrow = tmp->as_register();
- assert(UseCompressedOops, "swap is 32bit only");
- __ encode_heap_oop(obj, narrow);
- __ swap(as_Address(addr), narrow);
- __ decode_heap_oop(narrow, obj);
- } else {
- ShouldNotReachHere();
- }
-}
-
-#undef __
diff --git a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.hpp b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.hpp
deleted file mode 100644
index 0777ada12de..00000000000
--- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C1_LIRASSEMBLER_SPARC_HPP
-#define CPU_SPARC_C1_LIRASSEMBLER_SPARC_HPP
-
- private:
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Sparc load/store emission
- //
- // The sparc ld/st instructions cannot accomodate displacements > 13 bits long.
- // The following "pseudo" sparc instructions (load/store) make it easier to use the indexed addressing mode
- // by allowing 32 bit displacements:
- //
- // When disp <= 13 bits long, a single load or store instruction is emitted with (disp + [d]).
- // When disp > 13 bits long, code is emitted to set the displacement into the O7 register,
- // and then a load or store is emitted with ([O7] + [d]).
- //
-
- int store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned);
- int store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide);
-
- int load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned);
- int load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide);
-
- void monitorexit(LIR_Opr obj_opr, LIR_Opr lock_opr, Register hdr, int monitor_no);
-
- int shift_amount(BasicType t);
-
- static bool is_single_instruction(LIR_Op* op);
-
- // Record the type of the receiver in ReceiverTypeData
- void type_profile_helper(Register mdo, int mdo_offset_bias,
- ciMethodData *md, ciProfileData *data,
- Register recv, Register tmp1, Label* update_done);
- // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot.
- void setup_md_access(ciMethod* method, int bci,
- ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias);
-
- enum {
- _call_stub_size = 68,
- _call_aot_stub_size = 0,
- _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128),
- _deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64)
- };
-
- public:
- void pack64(LIR_Opr src, LIR_Opr dst);
- void unpack64(LIR_Opr src, LIR_Opr dst);
-
-#endif // CPU_SPARC_C1_LIRASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp
deleted file mode 100644
index 403f7cc5e52..00000000000
--- a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "c1/c1_Compilation.hpp"
-#include "c1/c1_FrameMap.hpp"
-#include "c1/c1_Instruction.hpp"
-#include "c1/c1_LIRAssembler.hpp"
-#include "c1/c1_LIRGenerator.hpp"
-#include "c1/c1_Runtime1.hpp"
-#include "c1/c1_ValueStack.hpp"
-#include "ci/ciArray.hpp"
-#include "ci/ciObjArrayKlass.hpp"
-#include "ci/ciTypeArrayKlass.hpp"
-#include "runtime/safepointMechanism.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "utilities/powerOfTwo.hpp"
-#include "vmreg_sparc.inline.hpp"
-
-#ifdef ASSERT
-#define __ gen()->lir(__FILE__, __LINE__)->
-#else
-#define __ gen()->lir()->
-#endif
-
-void LIRItem::load_byte_item() {
- // byte loads use same registers as other loads
- load_item();
-}
-
-
-void LIRItem::load_nonconstant() {
- LIR_Opr r = value()->operand();
- if (_gen->can_inline_as_constant(value())) {
- if (!r->is_constant()) {
- r = LIR_OprFact::value_type(value()->type());
- }
- _result = r;
- } else {
- load_item();
- }
-}
-
-
-//--------------------------------------------------------------
-// LIRGenerator
-//--------------------------------------------------------------
-
-LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::Oexception_opr; }
-LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::Oissuing_pc_opr; }
-LIR_Opr LIRGenerator::syncLockOpr() { return new_register(T_INT); }
-LIR_Opr LIRGenerator::syncTempOpr() { return new_register(T_OBJECT); }
-LIR_Opr LIRGenerator::getThreadTemp() { return rlock_callee_saved(T_LONG); }
-
-LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) {
- LIR_Opr opr;
- switch (type->tag()) {
- case intTag: opr = callee ? FrameMap::I0_opr : FrameMap::O0_opr; break;
- case objectTag: opr = callee ? FrameMap::I0_oop_opr : FrameMap::O0_oop_opr; break;
- case longTag: opr = callee ? FrameMap::in_long_opr : FrameMap::out_long_opr; break;
- case floatTag: opr = FrameMap::F0_opr; break;
- case doubleTag: opr = FrameMap::F0_double_opr; break;
-
- case addressTag:
- default: ShouldNotReachHere(); return LIR_OprFact::illegalOpr;
- }
-
- assert(opr->type_field() == as_OprType(as_BasicType(type)), "type mismatch");
- return opr;
-}
-
-LIR_Opr LIRGenerator::rlock_callee_saved(BasicType type) {
- LIR_Opr reg = new_register(type);
- set_vreg_flag(reg, callee_saved);
- return reg;
-}
-
-
-LIR_Opr LIRGenerator::rlock_byte(BasicType type) {
- return new_register(T_INT);
-}
-
-
-
-
-
-//--------- loading items into registers --------------------------------
-
-// SPARC cannot inline all constants
-bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const {
- if (v->type()->as_IntConstant() != NULL) {
- return v->type()->as_IntConstant()->value() == 0;
- } else if (v->type()->as_LongConstant() != NULL) {
- return v->type()->as_LongConstant()->value() == 0L;
- } else if (v->type()->as_ObjectConstant() != NULL) {
- return v->type()->as_ObjectConstant()->value()->is_null_object();
- } else {
- return false;
- }
-}
-
-
-// only simm13 constants can be inlined
-bool LIRGenerator:: can_inline_as_constant(Value i) const {
- if (i->type()->as_IntConstant() != NULL) {
- return Assembler::is_simm13(i->type()->as_IntConstant()->value());
- } else {
- return can_store_as_constant(i, as_BasicType(i->type()));
- }
-}
-
-
-bool LIRGenerator:: can_inline_as_constant(LIR_Const* c) const {
- if (c->type() == T_INT) {
- return Assembler::is_simm13(c->as_jint());
- }
- return false;
-}
-
-
-LIR_Opr LIRGenerator::safepoint_poll_register() {
- return new_register(T_INT);
-}
-
-
-
-LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
- int shift, int disp, BasicType type) {
- assert(base->is_register(), "must be");
- intx large_disp = disp;
-
- // accumulate fixed displacements
- if (index->is_constant()) {
- large_disp += (intx)(index->as_constant_ptr()->as_jint()) << shift;
- index = LIR_OprFact::illegalOpr;
- }
-
- if (index->is_register()) {
- // apply the shift and accumulate the displacement
- if (shift > 0) {
- LIR_Opr tmp = new_pointer_register();
- __ shift_left(index, shift, tmp);
- index = tmp;
- }
- if (large_disp != 0) {
- LIR_Opr tmp = new_pointer_register();
- if (Assembler::is_simm13(large_disp)) {
- __ add(tmp, LIR_OprFact::intptrConst(large_disp), tmp);
- index = tmp;
- } else {
- __ move(LIR_OprFact::intptrConst(large_disp), tmp);
- __ add(tmp, index, tmp);
- index = tmp;
- }
- large_disp = 0;
- }
- } else if (large_disp != 0 && !Assembler::is_simm13(large_disp)) {
- // index is illegal so replace it with the displacement loaded into a register
- index = new_pointer_register();
- __ move(LIR_OprFact::intptrConst(large_disp), index);
- large_disp = 0;
- }
-
- // at this point we either have base + index or base + displacement
- if (large_disp == 0) {
- return new LIR_Address(base, index, type);
- } else {
- assert(Assembler::is_simm13(large_disp), "must be");
- return new LIR_Address(base, large_disp, type);
- }
-}
-
-
-LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
- BasicType type) {
- int elem_size = type2aelembytes(type);
- int shift = exact_log2(elem_size);
-
- LIR_Opr base_opr;
- intx offset = arrayOopDesc::base_offset_in_bytes(type);
-
- if (index_opr->is_constant()) {
- intx i = index_opr->as_constant_ptr()->as_jint();
- intx array_offset = i * elem_size;
- if (Assembler::is_simm13(array_offset + offset)) {
- base_opr = array_opr;
- offset = array_offset + offset;
- } else {
- base_opr = new_pointer_register();
- if (Assembler::is_simm13(array_offset)) {
- __ add(array_opr, LIR_OprFact::intptrConst(array_offset), base_opr);
- } else {
- __ move(LIR_OprFact::intptrConst(array_offset), base_opr);
- __ add(base_opr, array_opr, base_opr);
- }
- }
- } else {
- if (index_opr->type() == T_INT) {
- LIR_Opr tmp = new_register(T_LONG);
- __ convert(Bytecodes::_i2l, index_opr, tmp);
- index_opr = tmp;
- }
-
- base_opr = new_pointer_register();
- assert (index_opr->is_register(), "Must be register");
- if (shift > 0) {
- __ shift_left(index_opr, shift, base_opr);
- __ add(base_opr, array_opr, base_opr);
- } else {
- __ add(index_opr, array_opr, base_opr);
- }
- }
-
- return new LIR_Address(base_opr, offset, type);
-}
-
-LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) {
- LIR_Opr r;
- if (type == T_LONG) {
- r = LIR_OprFact::longConst(x);
- } else if (type == T_INT) {
- r = LIR_OprFact::intConst(x);
- } else {
- ShouldNotReachHere();
- }
- if (!Assembler::is_simm13(x)) {
- LIR_Opr tmp = new_register(type);
- __ move(r, tmp);
- return tmp;
- }
- return r;
-}
-
-void LIRGenerator::increment_counter(address counter, BasicType type, int step) {
- LIR_Opr pointer = new_pointer_register();
- __ move(LIR_OprFact::intptrConst(counter), pointer);
- LIR_Address* addr = new LIR_Address(pointer, type);
- increment_counter(addr, step);
-}
-
-void LIRGenerator::increment_counter(LIR_Address* addr, int step) {
- LIR_Opr temp = new_register(addr->type());
- __ move(addr, temp);
- __ add(temp, load_immediate(step, addr->type()), temp);
- __ move(temp, addr);
-}
-
-void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) {
- LIR_Opr o7opr = FrameMap::O7_opr;
- __ load(new LIR_Address(base, disp, T_INT), o7opr, info);
- __ cmp(condition, o7opr, c);
-}
-
-
-void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, int disp, BasicType type, CodeEmitInfo* info) {
- LIR_Opr o7opr = FrameMap::O7_opr;
- __ load(new LIR_Address(base, disp, type), o7opr, info);
- __ cmp(condition, reg, o7opr);
-}
-
-
-bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) {
- assert(left != result, "should be different registers");
- if (is_power_of_2(c + 1)) {
- __ shift_left(left, log2_int(c + 1), result);
- __ sub(result, left, result);
- return true;
- } else if (is_power_of_2(c - 1)) {
- __ shift_left(left, log2_int(c - 1), result);
- __ add(result, left, result);
- return true;
- }
- return false;
-}
-
-
-void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) {
- BasicType t = item->type();
- LIR_Opr sp_opr = FrameMap::SP_opr;
- if ((t == T_LONG || t == T_DOUBLE) &&
- ((in_bytes(offset_from_sp) - STACK_BIAS) % 8 != 0)) {
- __ unaligned_move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t));
- } else {
- __ move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t));
- }
-}
-
-void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) {
- LIR_Opr tmp1 = FrameMap::G1_opr;
- LIR_Opr tmp2 = FrameMap::G3_opr;
- LIR_Opr tmp3 = FrameMap::G5_opr;
- __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
-}
-
-//----------------------------------------------------------------------
-// visitor functions
-//----------------------------------------------------------------------
-
-void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
- assert(x->is_pinned(),"");
- LIRItem obj(x->obj(), this);
- obj.load_item();
-
- set_no_result(x);
-
- LIR_Opr lock = FrameMap::G1_opr;
- LIR_Opr scratch = FrameMap::G3_opr;
- LIR_Opr hdr = FrameMap::G4_opr;
-
- CodeEmitInfo* info_for_exception = NULL;
- if (x->needs_null_check()) {
- info_for_exception = state_for(x);
- }
-
- // this CodeEmitInfo must not have the xhandlers because here the
- // object is already locked (xhandlers expects object to be unlocked)
- CodeEmitInfo* info = state_for(x, x->state(), true);
- monitor_enter(obj.result(), lock, hdr, scratch, x->monitor_no(), info_for_exception, info);
-}
-
-
-void LIRGenerator::do_MonitorExit(MonitorExit* x) {
- assert(x->is_pinned(),"");
- LIRItem obj(x->obj(), this);
- obj.dont_load_item();
-
- set_no_result(x);
- LIR_Opr lock = FrameMap::G1_opr;
- LIR_Opr hdr = FrameMap::G3_opr;
- LIR_Opr obj_temp = FrameMap::G4_opr;
- monitor_exit(obj_temp, lock, hdr, LIR_OprFact::illegalOpr, x->monitor_no());
-}
-
-
-// _ineg, _lneg, _fneg, _dneg
-void LIRGenerator::do_NegateOp(NegateOp* x) {
- LIRItem value(x->x(), this);
- value.load_item();
- LIR_Opr reg = rlock_result(x);
- __ negate(value.result(), reg);
-}
-
-
-
-// for _fadd, _fmul, _fsub, _fdiv, _frem
-// _dadd, _dmul, _dsub, _ddiv, _drem
-void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
- switch (x->op()) {
- case Bytecodes::_fadd:
- case Bytecodes::_fmul:
- case Bytecodes::_fsub:
- case Bytecodes::_fdiv:
- case Bytecodes::_dadd:
- case Bytecodes::_dmul:
- case Bytecodes::_dsub:
- case Bytecodes::_ddiv: {
- LIRItem left(x->x(), this);
- LIRItem right(x->y(), this);
- left.load_item();
- right.load_item();
- rlock_result(x);
- arithmetic_op_fpu(x->op(), x->operand(), left.result(), right.result(), x->is_strictfp());
- }
- break;
-
- case Bytecodes::_frem:
- case Bytecodes::_drem: {
- address entry;
- switch (x->op()) {
- case Bytecodes::_frem:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::frem);
- break;
- case Bytecodes::_drem:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::drem);
- break;
- default:
- ShouldNotReachHere();
- }
- LIR_Opr result = call_runtime(x->x(), x->y(), entry, x->type(), NULL);
- set_result(x, result);
- }
- break;
-
- default: ShouldNotReachHere();
- }
-}
-
-
-// for _ladd, _lmul, _lsub, _ldiv, _lrem
-void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
- switch (x->op()) {
- case Bytecodes::_lrem:
- case Bytecodes::_lmul:
- case Bytecodes::_ldiv: {
-
- if (x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem) {
- LIRItem right(x->y(), this);
- right.load_item();
-
- CodeEmitInfo* info = state_for(x);
- LIR_Opr item = right.result();
- assert(item->is_register(), "must be");
- __ cmp(lir_cond_equal, item, LIR_OprFact::longConst(0));
- __ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info));
- }
-
- address entry;
- switch (x->op()) {
- case Bytecodes::_lrem:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::lrem);
- break; // check if dividend is 0 is done elsewhere
- case Bytecodes::_ldiv:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::ldiv);
- break; // check if dividend is 0 is done elsewhere
- case Bytecodes::_lmul:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::lmul);
- break;
- default:
- ShouldNotReachHere();
- }
-
- // order of arguments to runtime call is reversed.
- LIR_Opr result = call_runtime(x->y(), x->x(), entry, x->type(), NULL);
- set_result(x, result);
- break;
- }
- case Bytecodes::_ladd:
- case Bytecodes::_lsub: {
- LIRItem left(x->x(), this);
- LIRItem right(x->y(), this);
- left.load_item();
- right.load_item();
- rlock_result(x);
-
- arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL);
- break;
- }
- default: ShouldNotReachHere();
- }
-}
-
-
-// Returns if item is an int constant that can be represented by a simm13
-static bool is_simm13(LIR_Opr item) {
- if (item->is_constant() && item->type() == T_INT) {
- return Assembler::is_simm13(item->as_constant_ptr()->as_jint());
- } else {
- return false;
- }
-}
-
-
-// for: _iadd, _imul, _isub, _idiv, _irem
-void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
- bool is_div_rem = x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem;
- LIRItem left(x->x(), this);
- LIRItem right(x->y(), this);
- // missing test if instr is commutative and if we should swap
- right.load_nonconstant();
- assert(right.is_constant() || right.is_register(), "wrong state of right");
- left.load_item();
- rlock_result(x);
- if (is_div_rem) {
- CodeEmitInfo* info = state_for(x);
- LIR_Opr tmp = FrameMap::G1_opr;
- if (x->op() == Bytecodes::_irem) {
- __ irem(left.result(), right.result(), x->operand(), tmp, info);
- } else if (x->op() == Bytecodes::_idiv) {
- __ idiv(left.result(), right.result(), x->operand(), tmp, info);
- }
- } else {
- arithmetic_op_int(x->op(), x->operand(), left.result(), right.result(), FrameMap::G1_opr);
- }
-}
-
-
-void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
- ValueTag tag = x->type()->tag();
- assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters");
- switch (tag) {
- case floatTag:
- case doubleTag: do_ArithmeticOp_FPU(x); return;
- case longTag: do_ArithmeticOp_Long(x); return;
- case intTag: do_ArithmeticOp_Int(x); return;
- }
- ShouldNotReachHere();
-}
-
-
-// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
-void LIRGenerator::do_ShiftOp(ShiftOp* x) {
- LIRItem value(x->x(), this);
- LIRItem count(x->y(), this);
- // Long shift destroys count register
- if (value.type()->is_long()) {
- count.set_destroys_register();
- }
- value.load_item();
- // the old backend doesn't support this
- if (count.is_constant() && count.type()->as_IntConstant() != NULL && value.type()->is_int()) {
- jint c = count.get_jint_constant() & 0x1f;
- assert(c >= 0 && c < 32, "should be small");
- count.dont_load_item();
- } else {
- count.load_item();
- }
- LIR_Opr reg = rlock_result(x);
- shift_op(x->op(), reg, value.result(), count.result(), LIR_OprFact::illegalOpr);
-}
-
-
-// _iand, _land, _ior, _lor, _ixor, _lxor
-void LIRGenerator::do_LogicOp(LogicOp* x) {
- LIRItem left(x->x(), this);
- LIRItem right(x->y(), this);
-
- left.load_item();
- right.load_nonconstant();
- LIR_Opr reg = rlock_result(x);
-
- logic_op(x->op(), reg, left.result(), right.result());
-}
-
-
-
-// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg
-void LIRGenerator::do_CompareOp(CompareOp* x) {
- LIRItem left(x->x(), this);
- LIRItem right(x->y(), this);
- left.load_item();
- right.load_item();
- LIR_Opr reg = rlock_result(x);
- if (x->x()->type()->is_float_kind()) {
- Bytecodes::Code code = x->op();
- __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl));
- } else if (x->x()->type()->tag() == longTag) {
- __ lcmp2int(left.result(), right.result(), reg);
- } else {
- Unimplemented();
- }
-}
-
-LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) {
- LIR_Opr result = new_register(T_INT);
- LIR_Opr t1 = FrameMap::G1_opr;
- LIR_Opr t2 = FrameMap::G3_opr;
- cmp_value.load_item();
- new_value.load_item();
- if (is_reference_type(type)) {
- __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
- } else if (type == T_INT) {
- __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
- } else if (type == T_LONG) {
- __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
- } else {
- Unimplemented();
- }
- __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0),
- result, type);
- return result;
-}
-
-LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
- bool is_obj = is_reference_type(type);
- LIR_Opr result = new_register(type);
- LIR_Opr tmp = LIR_OprFact::illegalOpr;
-
- value.load_item();
-
- if (is_obj) {
- tmp = FrameMap::G3_opr;
- }
-
- // Because we want a 2-arg form of xchg
- __ move(value.result(), result);
- __ xchg(addr, result, result, tmp);
- return result;
-}
-
-LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) {
- Unimplemented();
- return LIR_OprFact::illegalOpr;
-}
-
-void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
- switch (x->id()) {
- case vmIntrinsics::_dabs:
- case vmIntrinsics::_dsqrt: {
- assert(x->number_of_arguments() == 1, "wrong type");
- LIRItem value(x->argument_at(0), this);
- value.load_item();
- LIR_Opr dst = rlock_result(x);
-
- switch (x->id()) {
- case vmIntrinsics::_dsqrt: {
- __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr);
- break;
- }
- case vmIntrinsics::_dabs: {
- __ abs(value.result(), dst, LIR_OprFact::illegalOpr);
- break;
- }
- }
- break;
- }
- case vmIntrinsics::_dlog10: // fall through
- case vmIntrinsics::_dlog: // fall through
- case vmIntrinsics::_dsin: // fall through
- case vmIntrinsics::_dtan: // fall through
- case vmIntrinsics::_dcos: // fall through
- case vmIntrinsics::_dexp: {
- assert(x->number_of_arguments() == 1, "wrong type");
-
- address runtime_entry = NULL;
- switch (x->id()) {
- case vmIntrinsics::_dsin:
- runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
- break;
- case vmIntrinsics::_dcos:
- runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
- break;
- case vmIntrinsics::_dtan:
- runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
- break;
- case vmIntrinsics::_dlog:
- runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
- break;
- case vmIntrinsics::_dlog10:
- runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
- break;
- case vmIntrinsics::_dexp:
- runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
- break;
- default:
- ShouldNotReachHere();
- }
-
- LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL);
- set_result(x, result);
- break;
- }
- case vmIntrinsics::_dpow: {
- assert(x->number_of_arguments() == 2, "wrong type");
- address runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dpow);
- LIR_Opr result = call_runtime(x->argument_at(0), x->argument_at(1), runtime_entry, x->type(), NULL);
- set_result(x, result);
- break;
- }
- }
-}
-
-
-void LIRGenerator::do_ArrayCopy(Intrinsic* x) {
- assert(x->number_of_arguments() == 5, "wrong type");
-
- // Make all state_for calls early since they can emit code
- CodeEmitInfo* info = state_for(x, x->state());
-
- // Note: spill caller save before setting the item
- LIRItem src (x->argument_at(0), this);
- LIRItem src_pos (x->argument_at(1), this);
- LIRItem dst (x->argument_at(2), this);
- LIRItem dst_pos (x->argument_at(3), this);
- LIRItem length (x->argument_at(4), this);
- // load all values in callee_save_registers, as this makes the
- // parameter passing to the fast case simpler
- src.load_item_force (rlock_callee_saved(T_OBJECT));
- src_pos.load_item_force (rlock_callee_saved(T_INT));
- dst.load_item_force (rlock_callee_saved(T_OBJECT));
- dst_pos.load_item_force (rlock_callee_saved(T_INT));
- length.load_item_force (rlock_callee_saved(T_INT));
-
- int flags;
- ciArrayKlass* expected_type;
- arraycopy_helper(x, &flags, &expected_type);
-
- __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(),
- length.result(), rlock_callee_saved(T_INT),
- expected_type, flags, info);
- set_no_result(x);
-}
-
-void LIRGenerator::do_update_CRC32(Intrinsic* x) {
- // Make all state_for calls early since they can emit code
- LIR_Opr result = rlock_result(x);
- int flags = 0;
- switch (x->id()) {
- case vmIntrinsics::_updateCRC32: {
- LIRItem crc(x->argument_at(0), this);
- LIRItem val(x->argument_at(1), this);
- // val is destroyed by update_crc32
- val.set_destroys_register();
- crc.load_item();
- val.load_item();
- __ update_crc32(crc.result(), val.result(), result);
- break;
- }
- case vmIntrinsics::_updateBytesCRC32:
- case vmIntrinsics::_updateByteBufferCRC32: {
-
- bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32);
-
- LIRItem crc(x->argument_at(0), this);
- LIRItem buf(x->argument_at(1), this);
- LIRItem off(x->argument_at(2), this);
- LIRItem len(x->argument_at(3), this);
-
- buf.load_item();
- off.load_nonconstant();
-
- LIR_Opr index = off.result();
- int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0;
- if(off.result()->is_constant()) {
- index = LIR_OprFact::illegalOpr;
- offset += off.result()->as_jint();
- }
-
- LIR_Opr base_op = buf.result();
-
- if (index->is_valid()) {
- LIR_Opr tmp = new_register(T_LONG);
- __ convert(Bytecodes::_i2l, index, tmp);
- index = tmp;
- if (index->is_constant()) {
- offset += index->as_constant_ptr()->as_jint();
- index = LIR_OprFact::illegalOpr;
- } else if (index->is_register()) {
- LIR_Opr tmp2 = new_register(T_LONG);
- LIR_Opr tmp3 = new_register(T_LONG);
- __ move(base_op, tmp2);
- __ move(index, tmp3);
- __ add(tmp2, tmp3, tmp2);
- base_op = tmp2;
- } else {
- ShouldNotReachHere();
- }
- }
-
- LIR_Address* a = new LIR_Address(base_op, offset, T_BYTE);
-
- BasicTypeList signature(3);
- signature.append(T_INT);
- signature.append(T_ADDRESS);
- signature.append(T_INT);
- CallingConvention* cc = frame_map()->c_calling_convention(&signature);
- const LIR_Opr result_reg = result_register_for(x->type());
-
- LIR_Opr addr = new_pointer_register();
- __ leal(LIR_OprFact::address(a), addr);
-
- crc.load_item_force(cc->at(0));
- __ move(addr, cc->at(1));
- len.load_item_force(cc->at(2));
-
- __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), getThreadTemp(), result_reg, cc->args());
- __ move(result_reg, result);
-
- break;
- }
- default: {
- ShouldNotReachHere();
- }
- }
-}
-
-void LIRGenerator::do_update_CRC32C(Intrinsic* x) {
- // Make all state_for calls early since they can emit code
- LIR_Opr result = rlock_result(x);
- int flags = 0;
- switch (x->id()) {
- case vmIntrinsics::_updateBytesCRC32C:
- case vmIntrinsics::_updateDirectByteBufferCRC32C: {
-
- bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32C);
- int array_offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0;
-
- LIRItem crc(x->argument_at(0), this);
- LIRItem buf(x->argument_at(1), this);
- LIRItem off(x->argument_at(2), this);
- LIRItem end(x->argument_at(3), this);
-
- buf.load_item();
- off.load_nonconstant();
- end.load_nonconstant();
-
- // len = end - off
- LIR_Opr len = end.result();
- LIR_Opr tmpA = new_register(T_INT);
- LIR_Opr tmpB = new_register(T_INT);
- __ move(end.result(), tmpA);
- __ move(off.result(), tmpB);
- __ sub(tmpA, tmpB, tmpA);
- len = tmpA;
-
- LIR_Opr index = off.result();
-
- if(off.result()->is_constant()) {
- index = LIR_OprFact::illegalOpr;
- array_offset += off.result()->as_jint();
- }
-
- LIR_Opr base_op = buf.result();
-
- if (index->is_valid()) {
- LIR_Opr tmp = new_register(T_LONG);
- __ convert(Bytecodes::_i2l, index, tmp);
- index = tmp;
- if (index->is_constant()) {
- array_offset += index->as_constant_ptr()->as_jint();
- index = LIR_OprFact::illegalOpr;
- } else if (index->is_register()) {
- LIR_Opr tmp2 = new_register(T_LONG);
- LIR_Opr tmp3 = new_register(T_LONG);
- __ move(base_op, tmp2);
- __ move(index, tmp3);
- __ add(tmp2, tmp3, tmp2);
- base_op = tmp2;
- } else {
- ShouldNotReachHere();
- }
- }
-
- LIR_Address* a = new LIR_Address(base_op, array_offset, T_BYTE);
-
- BasicTypeList signature(3);
- signature.append(T_INT);
- signature.append(T_ADDRESS);
- signature.append(T_INT);
- CallingConvention* cc = frame_map()->c_calling_convention(&signature);
- const LIR_Opr result_reg = result_register_for(x->type());
-
- LIR_Opr addr = new_pointer_register();
- __ leal(LIR_OprFact::address(a), addr);
-
- crc.load_item_force(cc->at(0));
- __ move(addr, cc->at(1));
- __ move(len, cc->at(2));
-
- __ call_runtime_leaf(StubRoutines::updateBytesCRC32C(), getThreadTemp(), result_reg, cc->args());
- __ move(result_reg, result);
-
- break;
- }
- default: {
- ShouldNotReachHere();
- }
- }
-}
-
-void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
- assert(x->number_of_arguments() == 3, "wrong type");
- assert(UseFMA, "Needs FMA instructions support.");
-
- LIRItem a(x->argument_at(0), this);
- LIRItem b(x->argument_at(1), this);
- LIRItem c(x->argument_at(2), this);
-
- a.load_item();
- b.load_item();
- c.load_item();
-
- LIR_Opr ina = a.result();
- LIR_Opr inb = b.result();
- LIR_Opr inc = c.result();
- LIR_Opr res = rlock_result(x);
-
- switch (x->id()) {
- case vmIntrinsics::_fmaF: __ fmaf(ina, inb, inc, res); break;
- case vmIntrinsics::_fmaD: __ fmad(ina, inb, inc, res); break;
- default:
- ShouldNotReachHere();
- break;
- }
-}
-
-void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
- fatal("vectorizedMismatch intrinsic is not implemented on this platform");
-}
-
-// _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f
-// _i2b, _i2c, _i2s
-void LIRGenerator::do_Convert(Convert* x) {
-
- switch (x->op()) {
- case Bytecodes::_f2l:
- case Bytecodes::_d2l:
- case Bytecodes::_d2i:
- case Bytecodes::_l2f:
- case Bytecodes::_l2d: {
-
- address entry;
- switch (x->op()) {
- case Bytecodes::_l2f:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2f);
- break;
- case Bytecodes::_l2d:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2d);
- break;
- case Bytecodes::_f2l:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::f2l);
- break;
- case Bytecodes::_d2l:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::d2l);
- break;
- case Bytecodes::_d2i:
- entry = CAST_FROM_FN_PTR(address, SharedRuntime::d2i);
- break;
- default:
- ShouldNotReachHere();
- }
- LIR_Opr result = call_runtime(x->value(), entry, x->type(), NULL);
- set_result(x, result);
- break;
- }
-
- case Bytecodes::_i2f:
- case Bytecodes::_i2d: {
- LIRItem value(x->value(), this);
-
- LIR_Opr reg = rlock_result(x);
- // To convert an int to double, we need to load the 32-bit int
- // from memory into a single precision floating point register
- // (even numbered). Then the sparc fitod instruction takes care
- // of the conversion. This is a bit ugly, but is the best way to
- // get the int value in a single precision floating point register
- value.load_item();
- LIR_Opr tmp = force_to_spill(value.result(), T_FLOAT);
- __ convert(x->op(), tmp, reg);
- break;
- }
- break;
-
- case Bytecodes::_i2l:
- case Bytecodes::_i2b:
- case Bytecodes::_i2c:
- case Bytecodes::_i2s:
- case Bytecodes::_l2i:
- case Bytecodes::_f2d:
- case Bytecodes::_d2f: { // inline code
- LIRItem value(x->value(), this);
-
- value.load_item();
- LIR_Opr reg = rlock_result(x);
- __ convert(x->op(), value.result(), reg, false);
- }
- break;
-
- case Bytecodes::_f2i: {
- LIRItem value (x->value(), this);
- value.set_destroys_register();
- value.load_item();
- LIR_Opr reg = rlock_result(x);
- set_vreg_flag(reg, must_start_in_memory);
- __ convert(x->op(), value.result(), reg, false);
- }
- break;
-
- default: ShouldNotReachHere();
- }
-}
-
-
-void LIRGenerator::do_NewInstance(NewInstance* x) {
- print_if_not_loaded(x);
-
- // This instruction can be deoptimized in the slow path : use
- // O0 as result register.
- const LIR_Opr reg = result_register_for(x->type());
-
- CodeEmitInfo* info = state_for(x, x->state());
- LIR_Opr tmp1 = FrameMap::G1_oop_opr;
- LIR_Opr tmp2 = FrameMap::G3_oop_opr;
- LIR_Opr tmp3 = FrameMap::G4_oop_opr;
- LIR_Opr tmp4 = FrameMap::O1_oop_opr;
- LIR_Opr klass_reg = FrameMap::G5_metadata_opr;
- new_instance(reg, x->klass(), x->is_unresolved(), tmp1, tmp2, tmp3, tmp4, klass_reg, info);
- LIR_Opr result = rlock_result(x);
- __ move(reg, result);
-}
-
-
-void LIRGenerator::do_NewTypeArray(NewTypeArray* x) {
- // Evaluate state_for early since it may emit code
- CodeEmitInfo* info = state_for(x, x->state());
-
- LIRItem length(x->length(), this);
- length.load_item();
-
- LIR_Opr reg = result_register_for(x->type());
- LIR_Opr tmp1 = FrameMap::G1_oop_opr;
- LIR_Opr tmp2 = FrameMap::G3_oop_opr;
- LIR_Opr tmp3 = FrameMap::G4_oop_opr;
- LIR_Opr tmp4 = FrameMap::O1_oop_opr;
- LIR_Opr klass_reg = FrameMap::G5_metadata_opr;
- LIR_Opr len = length.result();
- BasicType elem_type = x->elt_type();
-
- __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg);
-
- CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info);
- __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path);
-
- LIR_Opr result = rlock_result(x);
- __ move(reg, result);
-}
-
-
-void LIRGenerator::do_NewObjectArray(NewObjectArray* x) {
- // Evaluate state_for early since it may emit code.
- CodeEmitInfo* info = state_for(x, x->state());
- // in case of patching (i.e., object class is not yet loaded), we need to reexecute the instruction
- // and therefore provide the state before the parameters have been consumed
- CodeEmitInfo* patching_info = NULL;
- if (!x->klass()->is_loaded() || PatchALot) {
- patching_info = state_for(x, x->state_before());
- }
-
- LIRItem length(x->length(), this);
- length.load_item();
-
- const LIR_Opr reg = result_register_for(x->type());
- LIR_Opr tmp1 = FrameMap::G1_oop_opr;
- LIR_Opr tmp2 = FrameMap::G3_oop_opr;
- LIR_Opr tmp3 = FrameMap::G4_oop_opr;
- LIR_Opr tmp4 = FrameMap::O1_oop_opr;
- LIR_Opr klass_reg = FrameMap::G5_metadata_opr;
- LIR_Opr len = length.result();
-
- CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info);
- ciMetadata* obj = ciObjArrayKlass::make(x->klass());
- if (obj == ciEnv::unloaded_ciobjarrayklass()) {
- BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error");
- }
- klass2reg_with_patching(klass_reg, obj, patching_info);
- __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path);
-
- LIR_Opr result = rlock_result(x);
- __ move(reg, result);
-}
-
-
-void LIRGenerator::do_NewMultiArray(NewMultiArray* x) {
- Values* dims = x->dims();
- int i = dims->length();
- LIRItemList* items = new LIRItemList(i, i, NULL);
- while (i-- > 0) {
- LIRItem* size = new LIRItem(dims->at(i), this);
- items->at_put(i, size);
- }
-
- // Evaluate state_for early since it may emit code.
- CodeEmitInfo* patching_info = NULL;
- if (!x->klass()->is_loaded() || PatchALot) {
- patching_info = state_for(x, x->state_before());
-
- // Cannot re-use same xhandlers for multiple CodeEmitInfos, so
- // clone all handlers (NOTE: Usually this is handled transparently
- // by the CodeEmitInfo cloning logic in CodeStub constructors but
- // is done explicitly here because a stub isn't being used).
- x->set_exception_handlers(new XHandlers(x->exception_handlers()));
- }
- CodeEmitInfo* info = state_for(x, x->state());
-
- i = dims->length();
- while (i-- > 0) {
- LIRItem* size = items->at(i);
- size->load_item();
- store_stack_parameter (size->result(),
- in_ByteSize(STACK_BIAS +
- frame::memory_parameter_word_sp_offset * wordSize +
- i * sizeof(jint)));
- }
-
- // This instruction can be deoptimized in the slow path : use
- // O0 as result register.
- const LIR_Opr klass_reg = FrameMap::O0_metadata_opr;
- klass2reg_with_patching(klass_reg, x->klass(), patching_info);
- LIR_Opr rank = FrameMap::O1_opr;
- __ move(LIR_OprFact::intConst(x->rank()), rank);
- LIR_Opr varargs = FrameMap::as_pointer_opr(O2);
- int offset_from_sp = (frame::memory_parameter_word_sp_offset * wordSize) + STACK_BIAS;
- __ add(FrameMap::SP_opr,
- LIR_OprFact::intptrConst(offset_from_sp),
- varargs);
- LIR_OprList* args = new LIR_OprList(3);
- args->append(klass_reg);
- args->append(rank);
- args->append(varargs);
- const LIR_Opr reg = result_register_for(x->type());
- __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id),
- LIR_OprFact::illegalOpr,
- reg, args, info);
-
- LIR_Opr result = rlock_result(x);
- __ move(reg, result);
-}
-
-
-void LIRGenerator::do_BlockBegin(BlockBegin* x) {
-}
-
-
-void LIRGenerator::do_CheckCast(CheckCast* x) {
- LIRItem obj(x->obj(), this);
- CodeEmitInfo* patching_info = NULL;
- if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) {
- // must do this before locking the destination register as an oop register,
- // and before the obj is loaded (so x->obj()->item() is valid for creating a debug info location)
- patching_info = state_for(x, x->state_before());
- }
- obj.load_item();
- LIR_Opr out_reg = rlock_result(x);
- CodeStub* stub;
- CodeEmitInfo* info_for_exception =
- (x->needs_exception_state() ? state_for(x) :
- state_for(x, x->state_before(), true /*ignore_xhandler*/));
-
- if (x->is_incompatible_class_change_check()) {
- assert(patching_info == NULL, "can't patch this");
- stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
- } else if (x->is_invokespecial_receiver_check()) {
- assert(patching_info == NULL, "can't patch this");
- stub = new DeoptimizeStub(info_for_exception,
- Deoptimization::Reason_class_check,
- Deoptimization::Action_none);
- } else {
- stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
- }
- LIR_Opr tmp1 = FrameMap::G1_oop_opr;
- LIR_Opr tmp2 = FrameMap::G3_oop_opr;
- LIR_Opr tmp3 = FrameMap::G4_oop_opr;
- __ checkcast(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3,
- x->direct_compare(), info_for_exception, patching_info, stub,
- x->profiled_method(), x->profiled_bci());
-}
-
-
-void LIRGenerator::do_InstanceOf(InstanceOf* x) {
- LIRItem obj(x->obj(), this);
- CodeEmitInfo* patching_info = NULL;
- if (!x->klass()->is_loaded() || PatchALot) {
- patching_info = state_for(x, x->state_before());
- }
- // ensure the result register is not the input register because the result is initialized before the patching safepoint
- obj.load_item();
- LIR_Opr out_reg = rlock_result(x);
- LIR_Opr tmp1 = FrameMap::G1_oop_opr;
- LIR_Opr tmp2 = FrameMap::G3_oop_opr;
- LIR_Opr tmp3 = FrameMap::G4_oop_opr;
- __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3,
- x->direct_compare(), patching_info,
- x->profiled_method(), x->profiled_bci());
-}
-
-
-void LIRGenerator::do_If(If* x) {
- assert(x->number_of_sux() == 2, "inconsistency");
- ValueTag tag = x->x()->type()->tag();
- LIRItem xitem(x->x(), this);
- LIRItem yitem(x->y(), this);
- LIRItem* xin = &xitem;
- LIRItem* yin = &yitem;
- If::Condition cond = x->cond();
-
- if (tag == longTag) {
- // for longs, only conditions "eql", "neq", "lss", "geq" are valid;
- // mirror for other conditions
- if (cond == If::gtr || cond == If::leq) {
- // swap inputs
- cond = Instruction::mirror(cond);
- xin = &yitem;
- yin = &xitem;
- }
- xin->set_destroys_register();
- }
-
- LIR_Opr left = LIR_OprFact::illegalOpr;
- LIR_Opr right = LIR_OprFact::illegalOpr;
-
- xin->load_item();
- left = xin->result();
-
- if (is_simm13(yin->result())) {
- // inline int constants which are small enough to be immediate operands
- right = LIR_OprFact::value_type(yin->value()->type());
- } else if (tag == longTag && yin->is_constant() && yin->get_jlong_constant() == 0 &&
- (cond == If::eql || cond == If::neq)) {
- // inline long zero
- right = LIR_OprFact::value_type(yin->value()->type());
- } else if (tag == objectTag && yin->is_constant() && (yin->get_jobject_constant()->is_null_object())) {
- right = LIR_OprFact::value_type(yin->value()->type());
- } else {
- yin->load_item();
- right = yin->result();
- }
- set_no_result(x);
-
- // add safepoint before generating condition code so it can be recomputed
- if (x->is_safepoint()) {
- // increment backedge counter if needed
- increment_backedge_counter_conditionally(lir_cond(cond), left, right, state_for(x, x->state_before()),
- x->tsux()->bci(), x->fsux()->bci(), x->profiled_bci());
- __ safepoint(safepoint_poll_register(), state_for(x, x->state_before()));
- }
-
- __ cmp(lir_cond(cond), left, right);
- // Generate branch profiling. Profiling code doesn't kill flags.
- profile_branch(x, cond);
- move_to_phi(x->state());
- if (x->x()->type()->is_float_kind()) {
- __ branch(lir_cond(cond), right->type(), x->tsux(), x->usux());
- } else {
- __ branch(lir_cond(cond), right->type(), x->tsux());
- }
- assert(x->default_sux() == x->fsux(), "wrong destination above");
- __ jump(x->default_sux());
-}
-
-
-LIR_Opr LIRGenerator::getThreadPointer() {
- return FrameMap::as_pointer_opr(G2);
-}
-
-
-void LIRGenerator::trace_block_entry(BlockBegin* block) {
- __ move(LIR_OprFact::intConst(block->block_id()), FrameMap::O0_opr);
- LIR_OprList* args = new LIR_OprList(1);
- args->append(FrameMap::O0_opr);
- address func = CAST_FROM_FN_PTR(address, Runtime1::trace_block_entry);
- __ call_runtime_leaf(func, rlock_callee_saved(T_INT), LIR_OprFact::illegalOpr, args);
-}
-
-
-void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address,
- CodeEmitInfo* info) {
- __ store(value, address, info);
-}
-
-void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
- CodeEmitInfo* info) {
- __ load(address, result, info);
-}
diff --git a/src/hotspot/cpu/sparc/c1_LIR_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIR_sparc.cpp
deleted file mode 100644
index c21d2c1d9ad..00000000000
--- a/src/hotspot/cpu/sparc/c1_LIR_sparc.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 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/register.hpp"
-#include "c1/c1_FrameMap.hpp"
-#include "c1/c1_LIR.hpp"
-
-FloatRegister LIR_OprDesc::as_float_reg() const {
- return FrameMap::nr2floatreg(fpu_regnr());
-}
-
-FloatRegister LIR_OprDesc::as_double_reg() const {
- return FrameMap::nr2floatreg(fpu_regnrHi());
-}
-
-LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) {
- assert(as_FloatRegister(reg2) != fnoreg, "Sparc holds double in two regs.");
- return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) |
- (reg2 << LIR_OprDesc::reg2_shift) |
- LIR_OprDesc::double_type |
- LIR_OprDesc::fpu_register |
- LIR_OprDesc::double_size);
-}
-
-#ifndef PRODUCT
-void LIR_Address::verify() const {
- assert(scale() == times_1, "Scaled addressing mode not available on SPARC and should not be used");
- assert(disp() == 0 || index()->is_illegal(), "can't have both");
- assert(base()->is_cpu_register(), "wrong base operand");
- assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand");
- assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
- "wrong type for addresses");
-}
-#endif // PRODUCT
diff --git a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.cpp b/src/hotspot/cpu/sparc/c1_LinearScan_sparc.cpp
deleted file mode 100644
index e09039e7e4c..00000000000
--- a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "c1/c1_Instruction.hpp"
-#include "c1/c1_LinearScan.hpp"
-#include "utilities/bitMap.inline.hpp"
-
-void LinearScan::allocate_fpu_stack() {
- // No FPU stack on SPARC
-}
diff --git a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.hpp b/src/hotspot/cpu/sparc/c1_LinearScan_sparc.hpp
deleted file mode 100644
index 9feabab963c..00000000000
--- a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.hpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C1_LINEARSCAN_SPARC_HPP
-#define CPU_SPARC_C1_LINEARSCAN_SPARC_HPP
-
-inline bool LinearScan::is_processed_reg_num(int reg_num) {
- return reg_num < 26 || reg_num > 31;
-}
-
-inline int LinearScan::num_physical_regs(BasicType type) {
- // Sparc requires two cpu registers for long
- // and two cpu registers for double
- if (type == T_DOUBLE) {
- return 2;
- }
- return 1;
-}
-
-
-inline bool LinearScan::requires_adjacent_regs(BasicType type) {
- return type == T_DOUBLE;
-}
-
-inline bool LinearScan::is_caller_save(int assigned_reg) {
- return assigned_reg > pd_last_callee_saved_reg && assigned_reg <= pd_last_fpu_reg;
-}
-
-
-inline void LinearScan::pd_add_temps(LIR_Op* op) {
- // No special case behaviours yet
-}
-
-
-inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) {
- if (allocator()->gen()->is_vreg_flag_set(cur->reg_num(), LIRGenerator::callee_saved)) {
- assert(cur->type() != T_FLOAT && cur->type() != T_DOUBLE, "cpu regs only");
- _first_reg = pd_first_callee_saved_reg;
- _last_reg = pd_last_callee_saved_reg;
- return true;
- } else if (cur->type() == T_INT || cur->type() == T_LONG || cur->type() == T_OBJECT || cur->type() == T_ADDRESS || cur->type() == T_METADATA) {
- _first_reg = pd_first_cpu_reg;
- _last_reg = pd_last_allocatable_cpu_reg;
- return true;
- }
- return false;
-}
-
-#endif // CPU_SPARC_C1_LINEARSCAN_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.cpp
deleted file mode 100644
index 615b388d16f..00000000000
--- a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "c1/c1_MacroAssembler.hpp"
-#include "c1/c1_Runtime1.hpp"
-#include "classfile/systemDictionary.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "interpreter/interpreter.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/markWord.hpp"
-#include "runtime/basicLock.hpp"
-#include "runtime/biasedLocking.hpp"
-#include "runtime/os.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-
-void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) {
- Label L;
- const Register temp_reg = G3_scratch;
- // Note: needs more testing of out-of-line vs. inline slow case
- verify_oop(receiver);
- load_klass(receiver, temp_reg);
- cmp_and_brx_short(temp_reg, iCache, Assembler::equal, Assembler::pt, L);
- AddressLiteral ic_miss(SharedRuntime::get_ic_miss_stub());
- jump_to(ic_miss, temp_reg);
- delayed()->nop();
- align(CodeEntryAlignment);
- bind(L);
-}
-
-
-void C1_MacroAssembler::explicit_null_check(Register base) {
- Unimplemented();
-}
-
-
-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");
- generate_stack_overflow_check(bang_size_in_bytes);
- // Create the frame.
- save_frame_c1(frame_size_in_bytes);
-}
-
-
-void C1_MacroAssembler::verified_entry() {
- if (C1Breakpoint) {
- breakpoint_trap();
- }
-}
-
-
-void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case) {
- assert_different_registers(Rmark, Roop, Rbox, Rscratch);
-
- Label done;
-
- Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
-
- // The following move must be the first instruction of emitted since debug
- // information may be generated for it.
- // Load object header
- ld_ptr(mark_addr, Rmark);
-
- verify_oop(Roop);
-
- // save object being locked into the BasicObjectLock
- st_ptr(Roop, Rbox, BasicObjectLock::obj_offset_in_bytes());
-
- if (UseBiasedLocking) {
- biased_locking_enter(Roop, Rmark, Rscratch, done, &slow_case);
- }
-
- // Save Rbox in Rscratch to be used for the cas operation
- mov(Rbox, Rscratch);
-
- // and mark it unlocked
- or3(Rmark, markWord::unlocked_value, Rmark);
-
- // save unlocked object header into the displaced header location on the stack
- st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
-
- // compare object markWord with Rmark and if equal exchange Rscratch with object markWord
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- cas_ptr(mark_addr.base(), Rmark, Rscratch);
- // if compare/exchange succeeded we found an unlocked object and we now have locked it
- // hence we are done
- cmp(Rmark, Rscratch);
- brx(Assembler::equal, false, Assembler::pt, done);
- delayed()->sub(Rscratch, SP, Rscratch); //pull next instruction into delay slot
- // we did not find an unlocked object so see if this is a recursive case
- // sub(Rscratch, SP, Rscratch);
- assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
- andcc(Rscratch, 0xfffff003, Rscratch);
- brx(Assembler::notZero, false, Assembler::pn, slow_case);
- delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
- bind(done);
-}
-
-
-void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) {
- assert_different_registers(Rmark, Roop, Rbox);
-
- Label done;
-
- Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
-
- if (UseBiasedLocking) {
- // load the object out of the BasicObjectLock
- ld_ptr(Rbox, BasicObjectLock::obj_offset_in_bytes(), Roop);
- verify_oop(Roop);
- biased_locking_exit(mark_addr, Rmark, done);
- }
- // Test first it it is a fast recursive unlock
- ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rmark);
- br_null_short(Rmark, Assembler::pt, done);
- if (!UseBiasedLocking) {
- // load object
- ld_ptr(Rbox, BasicObjectLock::obj_offset_in_bytes(), Roop);
- verify_oop(Roop);
- }
-
- // Check if it is still a light weight lock, this is is true if we see
- // the stack address of the basicLock in the markWord of the object
- cas_ptr(mark_addr.base(), Rbox, Rmark);
- cmp(Rbox, Rmark);
-
- brx(Assembler::notEqual, false, Assembler::pn, slow_case);
- delayed()->nop();
- // Done
- bind(done);
-}
-
-
-void C1_MacroAssembler::try_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register, must be global register for incr_allocated_bytes
- Register t2, // temp register
- Label& slow_case // continuation point if fast allocation fails
-) {
- RegisterOrConstant size_in_bytes = var_size_in_bytes->is_valid()
- ? RegisterOrConstant(var_size_in_bytes) : RegisterOrConstant(con_size_in_bytes);
- if (UseTLAB) {
- tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case);
- } else {
- eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case);
- incr_allocated_bytes(size_in_bytes, t1, t2);
- }
-}
-
-
-void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {
- assert_different_registers(obj, klass, len, t1, t2);
- if (UseBiasedLocking && !len->is_valid()) {
- ld_ptr(klass, in_bytes(Klass::prototype_header_offset()), t1);
- } else {
- set((intx)markWord::prototype().value(), t1);
- }
- st_ptr(t1, obj, oopDesc::mark_offset_in_bytes());
- if (UseCompressedClassPointers) {
- // Save klass
- mov(klass, t1);
- encode_klass_not_null(t1);
- stw(t1, obj, oopDesc::klass_offset_in_bytes());
- } else {
- st_ptr(klass, obj, oopDesc::klass_offset_in_bytes());
- }
- if (len->is_valid()) {
- st(len, obj, arrayOopDesc::length_offset_in_bytes());
- } else if (UseCompressedClassPointers) {
- // otherwise length is in the class gap
- store_klass_gap(G0, obj);
- }
-}
-
-
-void C1_MacroAssembler::initialize_body(Register base, Register index) {
- zero_memory(base, index);
-}
-
-
-void C1_MacroAssembler::allocate_object(
- Register obj, // result: pointer to object after successful allocation
- Register t1, // temp register
- Register t2, // temp register, must be a global register for try_allocate
- Register t3, // temp register
- int hdr_size, // object header size in words
- int obj_size, // object size in words
- Register klass, // object klass
- Label& slow_case // continuation point if fast allocation fails
-) {
- assert_different_registers(obj, t1, t2, t3, klass);
- assert(klass == G5, "must be G5");
-
- // allocate space & initialize header
- if (!is_simm13(obj_size * wordSize)) {
- // would need to use extra register to load
- // object size => go the slow case for now
- ba(slow_case);
- delayed()->nop();
- return;
- }
- try_allocate(obj, noreg, obj_size * wordSize, t2, t3, slow_case);
-
- initialize_object(obj, klass, noreg, obj_size * HeapWordSize, t1, t2, /* is_tlab_allocated */ UseTLAB);
-}
-
-void C1_MacroAssembler::initialize_object(
- Register obj, // result: pointer to object after successful allocation
- Register klass, // object klass
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- bool is_tlab_allocated // the object was allocated in a TLAB; relevant for the implementation of ZeroTLAB
- ) {
- const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;
-
- initialize_header(obj, klass, noreg, t1, t2);
-
-#ifdef ASSERT
- {
- Label ok;
- ld(klass, in_bytes(Klass::layout_helper_offset()), t1);
- if (var_size_in_bytes != noreg) {
- cmp_and_brx_short(t1, var_size_in_bytes, Assembler::equal, Assembler::pt, ok);
- } else {
- cmp_and_brx_short(t1, con_size_in_bytes, Assembler::equal, Assembler::pt, ok);
- }
- stop("bad size in initialize_object");
- should_not_reach_here();
-
- bind(ok);
- }
-
-#endif
-
- if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) {
- // initialize body
- const int threshold = 5 * HeapWordSize; // approximate break even point for code size
- if (var_size_in_bytes != noreg) {
- // use a loop
- add(obj, hdr_size_in_bytes, t1); // compute address of first element
- sub(var_size_in_bytes, hdr_size_in_bytes, t2); // compute size of body
- initialize_body(t1, t2);
- } else if (con_size_in_bytes <= threshold) {
- // use explicit NULL stores
- for (int i = hdr_size_in_bytes; i < con_size_in_bytes; i += HeapWordSize) st_ptr(G0, obj, i);
- } else if (con_size_in_bytes > hdr_size_in_bytes) {
- // use a loop
- const Register base = t1;
- const Register index = t2;
- add(obj, hdr_size_in_bytes, base); // compute address of first element
- // compute index = number of words to clear
- set(con_size_in_bytes - hdr_size_in_bytes, index);
- initialize_body(base, index);
- }
- }
-
- if (CURRENT_ENV->dtrace_alloc_probes()) {
- assert(obj == O0, "must be");
- call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)),
- relocInfo::runtime_call_type);
- delayed()->nop();
- }
-
- verify_oop(obj);
-}
-
-
-void C1_MacroAssembler::allocate_array(
- Register obj, // result: pointer to array after successful allocation
- Register len, // array length
- Register t1, // temp register
- Register t2, // temp register
- Register t3, // temp register
- int hdr_size, // object header size in words
- int elt_size, // element size in bytes
- Register klass, // object klass
- Label& slow_case // continuation point if fast allocation fails
-) {
- assert_different_registers(obj, len, t1, t2, t3, klass);
- assert(klass == G5, "must be G5");
- assert(t1 == G1, "must be G1");
-
- // determine alignment mask
- assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work");
-
- // check for negative or excessive length
- // note: the maximum length allowed is chosen so that arrays of any
- // element size with this length are always smaller or equal
- // to the largest integer (i.e., array size computation will
- // not overflow)
- set(max_array_allocation_length, t1);
- cmp(len, t1);
- br(Assembler::greaterUnsigned, false, Assembler::pn, slow_case);
-
- // compute array size
- // note: if 0 <= len <= max_length, len*elt_size + header + alignment is
- // smaller or equal to the largest integer; also, since top is always
- // aligned, we can do the alignment here instead of at the end address
- // computation
- const Register arr_size = t1;
- switch (elt_size) {
- case 1: delayed()->mov(len, arr_size); break;
- case 2: delayed()->sll(len, 1, arr_size); break;
- case 4: delayed()->sll(len, 2, arr_size); break;
- case 8: delayed()->sll(len, 3, arr_size); break;
- default: ShouldNotReachHere();
- }
- add(arr_size, hdr_size * wordSize + MinObjAlignmentInBytesMask, arr_size); // add space for header & alignment
- and3(arr_size, ~MinObjAlignmentInBytesMask, arr_size); // align array size
-
- // allocate space & initialize header
- if (UseTLAB) {
- tlab_allocate(obj, arr_size, 0, t2, slow_case);
- } else {
- eden_allocate(obj, arr_size, 0, t2, t3, slow_case);
- }
- initialize_header(obj, klass, len, t2, t3);
-
- // initialize body
- const Register base = t2;
- const Register index = t3;
- add(obj, hdr_size * wordSize, base); // compute address of first element
- sub(arr_size, hdr_size * wordSize, index); // compute index = number of words to clear
- initialize_body(base, index);
-
- if (CURRENT_ENV->dtrace_alloc_probes()) {
- assert(obj == O0, "must be");
- call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)),
- relocInfo::runtime_call_type);
- delayed()->nop();
- }
-
- verify_oop(obj);
-}
-
-
-#ifndef PRODUCT
-
-void C1_MacroAssembler::verify_stack_oop(int stack_offset) {
- if (!VerifyOops) return;
- verify_oop_addr(Address(SP, stack_offset + STACK_BIAS));
-}
-
-void C1_MacroAssembler::verify_not_null_oop(Register r) {
- Label not_null;
- br_notnull_short(r, Assembler::pt, not_null);
- stop("non-null oop required");
- bind(not_null);
- if (!VerifyOops) return;
- verify_oop(r);
-}
-
-void C1_MacroAssembler::invalidate_registers(bool iregisters, bool lregisters, bool oregisters,
- Register preserve1, Register preserve2) {
- if (iregisters) {
- for (int i = 0; i < 6; i++) {
- Register r = as_iRegister(i);
- if (r != preserve1 && r != preserve2) set(0xdead, r);
- }
- }
- if (oregisters) {
- for (int i = 0; i < 6; i++) {
- Register r = as_oRegister(i);
- if (r != preserve1 && r != preserve2) set(0xdead, r);
- }
- }
- if (lregisters) {
- for (int i = 0; i < 8; i++) {
- Register r = as_lRegister(i);
- if (r != preserve1 && r != preserve2) set(0xdead, r);
- }
- }
-}
-
-
-#endif
diff --git a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp
deleted file mode 100644
index 532ef0261df..00000000000
--- a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C1_MACROASSEMBLER_SPARC_HPP
-#define CPU_SPARC_C1_MACROASSEMBLER_SPARC_HPP
-
- void pd_init() { /* nothing to do */ }
-
- public:
- void try_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- Label& slow_case // continuation point if fast allocation fails
- );
-
- void initialize_header(Register obj, Register klass, Register len, Register t1, Register t2);
- void initialize_body(Register base, Register index);
-
- // locking/unlocking
- void lock_object (Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case);
- void unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case);
-
- void initialize_object(
- Register obj, // result: pointer to object after successful allocation
- Register klass, // object klass
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- bool is_tlab_allocated // the object was allocated in a TLAB; relevant for the implementation of ZeroTLAB
- );
-
- // allocation of fixed-size objects
- // (can also be used to allocate fixed-size arrays, by setting
- // hdr_size correctly and storing the array length afterwards)
- void allocate_object(
- Register obj, // result: pointer to object after successful allocation
- Register t1, // temp register
- Register t2, // temp register
- Register t3, // temp register
- int hdr_size, // object header size in words
- int obj_size, // object size in words
- Register klass, // object klass
- Label& slow_case // continuation point if fast allocation fails
- );
-
- enum {
- max_array_allocation_length = 0x01000000 // sparc friendly value, requires sethi only
- };
-
- // allocation of arrays
- void allocate_array(
- Register obj, // result: pointer to array after successful allocation
- Register len, // array length
- Register t1, // temp register
- Register t2, // temp register
- Register t3, // temp register
- int hdr_size, // object header size in words
- int elt_size, // element size in bytes
- Register klass, // object klass
- Label& slow_case // continuation point if fast allocation fails
- );
-
- // invalidates registers in this window
- void invalidate_registers(bool iregisters, bool lregisters, bool oregisters,
- Register preserve1 = noreg, Register preserve2 = noreg);
-
- // This platform only uses signal-based null checks. The Label is not needed.
- void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); }
-
- void save_live_registers_no_oop_map(bool save_fpu_registers);
- void restore_live_registers(bool restore_fpu_registers);
-
-#endif // CPU_SPARC_C1_MACROASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp
deleted file mode 100644
index b0c0b2d7f1d..00000000000
--- a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp
+++ /dev/null
@@ -1,917 +0,0 @@
-/*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "c1/c1_Defs.hpp"
-#include "c1/c1_MacroAssembler.hpp"
-#include "c1/c1_Runtime1.hpp"
-#include "ci/ciUtilities.hpp"
-#include "gc/shared/cardTable.hpp"
-#include "gc/shared/cardTableBarrierSet.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/universe.hpp"
-#include "nativeInst_sparc.hpp"
-#include "oops/compiledICHolder.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/signature.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/macros.hpp"
-#include "utilities/align.hpp"
-#include "vmreg_sparc.inline.hpp"
-
-// Implementation of StubAssembler
-
-int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry_point, int number_of_arguments) {
- // for sparc changing the number of arguments doesn't change
- // anything about the frame size so we'll always lie and claim that
- // we are only passing 1 argument.
- set_num_rt_args(1);
-
- assert_not_delayed();
- // bang stack before going to runtime
- set(-os::vm_page_size() + STACK_BIAS, G3_scratch);
- st(G0, SP, G3_scratch);
-
- // debugging support
- assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
-
- set_last_Java_frame(SP, noreg);
- if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early
- save_thread(L7_thread_cache);
- // do the call
- call(entry_point, relocInfo::runtime_call_type);
- if (!VerifyThread) {
- delayed()->mov(G2_thread, O0); // pass thread as first argument
- } else {
- delayed()->nop(); // (thread already passed)
- }
- int call_offset = offset(); // offset of return address
- restore_thread(L7_thread_cache);
- reset_last_Java_frame();
-
- // check for pending exceptions
- { Label L;
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- ld_ptr(exception_addr, Gtemp);
- br_null_short(Gtemp, pt, L);
- Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
- st_ptr(G0, vm_result_addr);
- Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset());
- st_ptr(G0, vm_result_addr_2);
-
- if (frame_size() == no_frame_size) {
- // we use O7 linkage so that forward_exception_entry has the issuing PC
- call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type);
- delayed()->restore();
- } else if (_stub_id == Runtime1::forward_exception_id) {
- should_not_reach_here();
- } else {
- AddressLiteral exc(Runtime1::entry_for(Runtime1::forward_exception_id));
- jump_to(exc, G4);
- delayed()->nop();
- }
- bind(L);
- }
-
- // get oop result if there is one and reset the value in the thread
- if (oop_result1->is_valid()) { // get oop result if there is one and reset it in the thread
- get_vm_result (oop_result1);
- } else {
- // be a little paranoid and clear the result
- Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
- st_ptr(G0, vm_result_addr);
- }
-
- // get second result if there is one and reset the value in the thread
- if (metadata_result->is_valid()) {
- get_vm_result_2 (metadata_result);
- } else {
- // be a little paranoid and clear the result
- Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset());
- st_ptr(G0, vm_result_addr_2);
- }
-
- return call_offset;
-}
-
-
-int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) {
- // O0 is reserved for the thread
- mov(arg1, O1);
- return call_RT(oop_result1, metadata_result, entry, 1);
-}
-
-
-int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) {
- // O0 is reserved for the thread
- mov(arg1, O1);
- mov(arg2, O2); assert(arg2 != O1, "smashed argument");
- return call_RT(oop_result1, metadata_result, entry, 2);
-}
-
-
-int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) {
- // O0 is reserved for the thread
- mov(arg1, O1);
- mov(arg2, O2); assert(arg2 != O1, "smashed argument");
- mov(arg3, O3); assert(arg3 != O1 && arg3 != O2, "smashed argument");
- return call_RT(oop_result1, metadata_result, entry, 3);
-}
-
-void StubAssembler::prologue(const char* name, bool must_gc_arguments) {
- set_info(name, must_gc_arguments);
-}
-
-void StubAssembler::epilogue() {
- delayed()->restore();
-}
-
-// Implementation of Runtime1
-
-
-static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs];
-static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs];
-static int reg_save_size_in_words;
-static int frame_size_in_bytes = -1;
-
-static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) {
- assert(frame_size_in_bytes == sasm->total_frame_size_in_bytes(reg_save_size_in_words),
- "mismatch in calculation");
- sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
- int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
- OopMap* oop_map = new OopMap(frame_size_in_slots, 0);
-
- int i;
- for (i = 0; i < FrameMap::nof_cpu_regs; i++) {
- Register r = as_Register(i);
- if (r == G1 || r == G3 || r == G4 || r == G5) {
- int sp_offset = cpu_reg_save_offsets[i];
- oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset),
- r->as_VMReg());
- }
- }
-
- if (save_fpu_registers) {
- for (i = 0; i < FrameMap::nof_fpu_regs; i++) {
- FloatRegister r = as_FloatRegister(i);
- int sp_offset = fpu_reg_save_offsets[i];
- oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset),
- r->as_VMReg());
- }
- }
- return oop_map;
-}
-
-#define __ this->
-
-void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) {
- assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words),
- "mismatch in calculation");
- __ save_frame_c1(frame_size_in_bytes);
-
- // Record volatile registers as callee-save values in an OopMap so their save locations will be
- // propagated to the caller frame's RegisterMap during StackFrameStream construction (needed for
- // deoptimization; see compiledVFrame::create_stack_value). The caller's I, L and O registers
- // are saved in register windows - I's and L's in the caller's frame and O's in the stub frame
- // (as the stub's I's) when the runtime routine called by the stub creates its frame.
- // OopMap frame sizes are in c2 stack slot sizes (sizeof(jint))
-
- int i;
- for (i = 0; i < FrameMap::nof_cpu_regs; i++) {
- Register r = as_Register(i);
- if (r == G1 || r == G3 || r == G4 || r == G5) {
- int sp_offset = cpu_reg_save_offsets[i];
- __ st_ptr(r, SP, (sp_offset * BytesPerWord) + STACK_BIAS);
- }
- }
-
- if (save_fpu_registers) {
- for (i = 0; i < FrameMap::nof_fpu_regs; i++) {
- FloatRegister r = as_FloatRegister(i);
- int sp_offset = fpu_reg_save_offsets[i];
- __ stf(FloatRegisterImpl::S, r, SP, (sp_offset * BytesPerWord) + STACK_BIAS);
- }
- }
-}
-
-void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) {
- for (int i = 0; i < FrameMap::nof_cpu_regs; i++) {
- Register r = as_Register(i);
- if (r == G1 || r == G3 || r == G4 || r == G5) {
- __ ld_ptr(SP, (cpu_reg_save_offsets[i] * BytesPerWord) + STACK_BIAS, r);
- }
- }
-
- if (restore_fpu_registers) {
- for (int i = 0; i < FrameMap::nof_fpu_regs; i++) {
- FloatRegister r = as_FloatRegister(i);
- __ ldf(FloatRegisterImpl::S, SP, (fpu_reg_save_offsets[i] * BytesPerWord) + STACK_BIAS, r);
- }
- }
-}
-
-#undef __
-#define __ sasm->
-
-static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) {
- __ save_live_registers_no_oop_map(save_fpu_registers);
- return generate_oop_map(sasm, save_fpu_registers);
-}
-
-static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) {
- __ restore_live_registers(restore_fpu_registers);
-}
-
-
-void Runtime1::initialize_pd() {
- // compute word offsets from SP at which live (non-windowed) registers are captured by stub routines
- //
- // A stub routine will have a frame that is at least large enough to hold
- // a register window save area (obviously) and the volatile g registers
- // and floating registers. A user of save_live_registers can have a frame
- // that has more scratch area in it (although typically they will use L-regs).
- // in that case the frame will look like this (stack growing down)
- //
- // FP -> | |
- // | scratch mem |
- // | " " |
- // --------------
- // | float regs |
- // | " " |
- // ---------------
- // | G regs |
- // | " " |
- // ---------------
- // | abi reg. |
- // | window save |
- // | area |
- // SP -> ---------------
- //
- int i;
- int sp_offset = align_up((int)frame::register_save_words, 2); // start doubleword aligned
-
- // only G int registers are saved explicitly; others are found in register windows
- for (i = 0; i < FrameMap::nof_cpu_regs; i++) {
- Register r = as_Register(i);
- if (r == G1 || r == G3 || r == G4 || r == G5) {
- cpu_reg_save_offsets[i] = sp_offset;
- sp_offset++;
- }
- }
-
- // all float registers are saved explicitly
- assert(FrameMap::nof_fpu_regs == 32, "double registers not handled here");
- for (i = 0; i < FrameMap::nof_fpu_regs; i++) {
- fpu_reg_save_offsets[i] = sp_offset;
- sp_offset++;
- }
- reg_save_size_in_words = sp_offset - frame::memory_parameter_word_sp_offset;
- // this should match assembler::total_frame_size_in_bytes, which
- // isn't callable from this context. It's checked by an assert when
- // it's used though.
- frame_size_in_bytes = align_up(sp_offset * wordSize, 8);
-}
-
-
-OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {
- // make a frame and preserve the caller's caller-save registers
- OopMap* oop_map = save_live_registers(sasm);
- int call_offset;
- if (!has_argument) {
- call_offset = __ call_RT(noreg, noreg, target);
- } else {
- call_offset = __ call_RT(noreg, noreg, target, G4, G5);
- }
- OopMapSet* oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
-
- __ should_not_reach_here();
- return oop_maps;
-}
-
-
-OopMapSet* Runtime1::generate_stub_call(StubAssembler* sasm, Register result, address target,
- Register arg1, Register arg2, Register arg3) {
- // make a frame and preserve the caller's caller-save registers
- OopMap* oop_map = save_live_registers(sasm);
-
- int call_offset;
- if (arg1 == noreg) {
- call_offset = __ call_RT(result, noreg, target);
- } else if (arg2 == noreg) {
- call_offset = __ call_RT(result, noreg, target, arg1);
- } else if (arg3 == noreg) {
- call_offset = __ call_RT(result, noreg, target, arg1, arg2);
- } else {
- call_offset = __ call_RT(result, noreg, target, arg1, arg2, arg3);
- }
- OopMapSet* oop_maps = NULL;
-
- oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
- restore_live_registers(sasm);
-
- __ ret();
- __ delayed()->restore();
-
- return oop_maps;
-}
-
-
-OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
- // make a frame and preserve the caller's caller-save registers
- OopMap* oop_map = save_live_registers(sasm);
-
- // call the runtime patching routine, returns non-zero if nmethod got deopted.
- int call_offset = __ call_RT(noreg, noreg, target);
- OopMapSet* oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
-
- // re-execute the patched instruction or, if the nmethod was deoptmized, return to the
- // deoptimization handler entry that will cause re-execution of the current bytecode
- DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
- assert(deopt_blob != NULL, "deoptimization blob must have been created");
-
- Label no_deopt;
- __ br_null_short(O0, Assembler::pt, no_deopt);
-
- // return to the deoptimization handler entry for unpacking and rexecute
- // if we simply returned the we'd deopt as if any call we patched had just
- // returned.
-
- restore_live_registers(sasm);
-
- AddressLiteral dest(deopt_blob->unpack_with_reexecution());
- __ jump_to(dest, O0);
- __ delayed()->restore();
-
- __ bind(no_deopt);
- restore_live_registers(sasm);
- __ ret();
- __ delayed()->restore();
-
- return oop_maps;
-}
-
-OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
-
- OopMapSet* oop_maps = NULL;
- // for better readability
- const bool must_gc_arguments = true;
- const bool dont_gc_arguments = false;
-
- // stub code & info for the different stubs
- switch (id) {
- case forward_exception_id:
- {
- oop_maps = generate_handle_exception(id, sasm);
- }
- break;
-
- case new_instance_id:
- case fast_new_instance_id:
- case fast_new_instance_init_check_id:
- {
- Register G5_klass = G5; // Incoming
- Register O0_obj = O0; // Outgoing
-
- if (id == new_instance_id) {
- __ set_info("new_instance", dont_gc_arguments);
- } else if (id == fast_new_instance_id) {
- __ set_info("fast new_instance", dont_gc_arguments);
- } else {
- assert(id == fast_new_instance_init_check_id, "bad StubID");
- __ set_info("fast new_instance init check", dont_gc_arguments);
- }
-
- // If TLAB is disabled, see if there is support for inlining contiguous
- // allocations.
- // Otherwise, just go to the slow path.
- if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) &&
- !UseTLAB && Universe::heap()->supports_inline_contig_alloc()) {
- Label slow_path;
- Register G1_obj_size = G1;
- Register G3_t1 = G3;
- Register G4_t2 = G4;
- assert_different_registers(G5_klass, G1_obj_size, G3_t1, G4_t2);
-
- // Push a frame since we may do dtrace notification for the
- // allocation which requires calling out and we don't want
- // to stomp the real return address.
- __ save_frame(0);
-
- if (id == fast_new_instance_init_check_id) {
- // make sure the klass is initialized
- __ ldub(G5_klass, in_bytes(InstanceKlass::init_state_offset()), G3_t1);
- __ cmp(G3_t1, InstanceKlass::fully_initialized);
- __ br(Assembler::notEqual, false, Assembler::pn, slow_path);
- __ delayed()->nop();
- }
-#ifdef ASSERT
- // assert object can be fast path allocated
- {
- Label ok, not_ok;
- __ ld(G5_klass, in_bytes(Klass::layout_helper_offset()), G1_obj_size);
- // make sure it's an instance (LH > 0)
- __ cmp_and_br_short(G1_obj_size, 0, Assembler::lessEqual, Assembler::pn, not_ok);
- __ btst(Klass::_lh_instance_slow_path_bit, G1_obj_size);
- __ br(Assembler::zero, false, Assembler::pn, ok);
- __ delayed()->nop();
- __ bind(not_ok);
- __ stop("assert(can be fast path allocated)");
- __ should_not_reach_here();
- __ bind(ok);
- }
-#endif // ASSERT
-
- // If we got here then the TLAB allocation failed, so try allocating directly from eden.
- // get the instance size
- __ ld(G5_klass, in_bytes(Klass::layout_helper_offset()), G1_obj_size);
- __ eden_allocate(O0_obj, G1_obj_size, 0, G3_t1, G4_t2, slow_path);
- __ incr_allocated_bytes(G1_obj_size, G3_t1, G4_t2);
-
- __ initialize_object(O0_obj, G5_klass, G1_obj_size, 0, G3_t1, G4_t2, /* is_tlab_allocated */ false);
- __ verify_oop(O0_obj);
- __ mov(O0, I0);
- __ ret();
- __ delayed()->restore();
-
- __ bind(slow_path);
-
- // pop this frame so generate_stub_call can push it's own
- __ restore();
- }
-
- oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_instance), G5_klass);
- // I0->O0: new instance
- }
-
- break;
-
- case counter_overflow_id:
- // G4 contains bci, G5 contains method
- oop_maps = generate_stub_call(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), G4, G5);
- break;
-
- case new_type_array_id:
- case new_object_array_id:
- {
- Register G5_klass = G5; // Incoming
- Register G4_length = G4; // Incoming
- Register O0_obj = O0; // Outgoing
-
- Address klass_lh(G5_klass, Klass::layout_helper_offset());
- assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise");
- assert(Klass::_lh_header_size_mask == 0xFF, "bytewise");
- // Use this offset to pick out an individual byte of the layout_helper:
- const int klass_lh_header_size_offset = ((BytesPerInt - 1) // 3 - 2 selects byte {0,1,0,0}
- - Klass::_lh_header_size_shift / BitsPerByte);
-
- if (id == new_type_array_id) {
- __ set_info("new_type_array", dont_gc_arguments);
- } else {
- __ set_info("new_object_array", dont_gc_arguments);
- }
-
-#ifdef ASSERT
- // assert object type is really an array of the proper kind
- {
- Label ok;
- Register G3_t1 = G3;
- __ ld(klass_lh, G3_t1);
- __ sra(G3_t1, Klass::_lh_array_tag_shift, G3_t1);
- int tag = ((id == new_type_array_id)
- ? Klass::_lh_array_tag_type_value
- : Klass::_lh_array_tag_obj_value);
- __ cmp_and_brx_short(G3_t1, tag, Assembler::equal, Assembler::pt, ok);
- __ stop("assert(is an array klass)");
- __ should_not_reach_here();
- __ bind(ok);
- }
-#endif // ASSERT
-
- if (id == new_type_array_id) {
- oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_type_array), G5_klass, G4_length);
- } else {
- oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_object_array), G5_klass, G4_length);
- }
- // I0 -> O0: new array
- }
- break;
-
- case new_multi_array_id:
- { // O0: klass
- // O1: rank
- // O2: address of 1st dimension
- __ set_info("new_multi_array", dont_gc_arguments);
- oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_multi_array), I0, I1, I2);
- // I0 -> O0: new multi array
- }
- break;
-
- case register_finalizer_id:
- {
- __ set_info("register_finalizer", dont_gc_arguments);
-
- // load the klass and check the has finalizer flag
- Label register_finalizer;
- Register t = O1;
- __ load_klass(O0, t);
- __ ld(t, in_bytes(Klass::access_flags_offset()), t);
- __ set(JVM_ACC_HAS_FINALIZER, G3);
- __ andcc(G3, t, G0);
- __ br(Assembler::notZero, false, Assembler::pt, register_finalizer);
- __ delayed()->nop();
-
- // do a leaf return
- __ retl();
- __ delayed()->nop();
-
- __ bind(register_finalizer);
- OopMap* oop_map = save_live_registers(sasm);
- int call_offset = __ call_RT(noreg, noreg,
- CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), I0);
- oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
-
- // Now restore all the live registers
- restore_live_registers(sasm);
-
- __ ret();
- __ delayed()->restore();
- }
- break;
-
- case throw_range_check_failed_id:
- { __ set_info("range_check_failed", dont_gc_arguments); // arguments will be discarded
- // G4: index
- oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true);
- }
- break;
-
- case throw_index_exception_id:
- { __ set_info("index_range_check_failed", dont_gc_arguments); // arguments will be discarded
- // G4: index
- oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true);
- }
- break;
-
- case throw_div0_exception_id:
- { __ set_info("throw_div0_exception", dont_gc_arguments);
- oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false);
- }
- break;
-
- case throw_null_pointer_exception_id:
- { __ set_info("throw_null_pointer_exception", dont_gc_arguments);
- oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false);
- }
- break;
-
- case handle_exception_id:
- { __ set_info("handle_exception", dont_gc_arguments);
- oop_maps = generate_handle_exception(id, sasm);
- }
- break;
-
- case handle_exception_from_callee_id:
- { __ set_info("handle_exception_from_callee", dont_gc_arguments);
- oop_maps = generate_handle_exception(id, sasm);
- }
- break;
-
- case unwind_exception_id:
- {
- // O0: exception
- // I7: address of call to this method
-
- __ set_info("unwind_exception", dont_gc_arguments);
- __ mov(Oexception, Oexception->after_save());
- __ add(I7, frame::pc_return_offset, Oissuing_pc->after_save());
-
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
- G2_thread, Oissuing_pc->after_save());
- __ verify_not_null_oop(Oexception->after_save());
-
- // Restore SP from L7 if the exception PC is a method handle call site.
- __ mov(O0, G5); // Save the target address.
- __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0);
- __ tst(L0); // Condition codes are preserved over the restore.
- __ restore();
-
- __ jmp(G5, 0);
- __ delayed()->movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // Restore SP if required.
- }
- break;
-
- case throw_array_store_exception_id:
- {
- __ set_info("throw_array_store_exception", dont_gc_arguments);
- oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true);
- }
- break;
-
- case throw_class_cast_exception_id:
- {
- // G4: object
- __ set_info("throw_class_cast_exception", dont_gc_arguments);
- oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
- }
- break;
-
- case throw_incompatible_class_change_error_id:
- {
- __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments);
- oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
- }
- break;
-
- case slow_subtype_check_id:
- { // Support for uint StubRoutine::partial_subtype_check( Klass sub, Klass super );
- // Arguments :
- //
- // ret : G3
- // sub : G3, argument, destroyed
- // super: G1, argument, not changed
- // raddr: O7, blown by call
- Label miss;
-
- __ save_frame(0); // Blow no registers!
-
- __ check_klass_subtype_slow_path(G3, G1, L0, L1, L2, L4, NULL, &miss);
-
- __ mov(1, G3);
- __ ret(); // Result in G5 is 'true'
- __ delayed()->restore(); // free copy or add can go here
-
- __ bind(miss);
- __ mov(0, G3);
- __ ret(); // Result in G5 is 'false'
- __ delayed()->restore(); // free copy or add can go here
- }
-
- case monitorenter_nofpu_id:
- case monitorenter_id:
- { // G4: object
- // G5: lock address
- __ set_info("monitorenter", dont_gc_arguments);
-
- int save_fpu_registers = (id == monitorenter_id);
- // make a frame and preserve the caller's caller-save registers
- OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
-
- int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), G4, G5);
-
- oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
- restore_live_registers(sasm, save_fpu_registers);
-
- __ ret();
- __ delayed()->restore();
- }
- break;
-
- case monitorexit_nofpu_id:
- case monitorexit_id:
- { // G4: lock address
- // note: really a leaf routine but must setup last java sp
- // => use call_RT for now (speed can be improved by
- // doing last java sp setup manually)
- __ set_info("monitorexit", dont_gc_arguments);
-
- int save_fpu_registers = (id == monitorexit_id);
- // make a frame and preserve the caller's caller-save registers
- OopMap* oop_map = save_live_registers(sasm, save_fpu_registers);
-
- int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), G4);
-
- oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
- restore_live_registers(sasm, save_fpu_registers);
-
- __ ret();
- __ delayed()->restore();
- }
- break;
-
- case deoptimize_id:
- {
- __ set_info("deoptimize", dont_gc_arguments);
- OopMap* oop_map = save_live_registers(sasm);
- int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize), G4);
- oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
- restore_live_registers(sasm);
- DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
- assert(deopt_blob != NULL, "deoptimization blob must have been created");
- AddressLiteral dest(deopt_blob->unpack_with_reexecution());
- __ jump_to(dest, O0);
- __ delayed()->restore();
- }
- break;
-
- case access_field_patching_id:
- { __ set_info("access_field_patching", dont_gc_arguments);
- oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching));
- }
- break;
-
- case load_klass_patching_id:
- { __ set_info("load_klass_patching", dont_gc_arguments);
- oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching));
- }
- break;
-
- case load_mirror_patching_id:
- { __ set_info("load_mirror_patching", dont_gc_arguments);
- oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching));
- }
- break;
-
- case load_appendix_patching_id:
- { __ set_info("load_appendix_patching", dont_gc_arguments);
- oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching));
- }
- break;
-
- case dtrace_object_alloc_id:
- { // O0: object
- __ set_info("dtrace_object_alloc", dont_gc_arguments);
- // we can't gc here so skip the oopmap but make sure that all
- // the live registers get saved.
- save_live_registers(sasm);
-
- __ save_thread(L7_thread_cache);
- __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc),
- relocInfo::runtime_call_type);
- __ delayed()->mov(I0, O0);
- __ restore_thread(L7_thread_cache);
-
- restore_live_registers(sasm);
- __ ret();
- __ delayed()->restore();
- }
- break;
-
- case predicate_failed_trap_id:
- {
- __ set_info("predicate_failed_trap", dont_gc_arguments);
- OopMap* oop_map = save_live_registers(sasm);
-
- int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap));
-
- oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, oop_map);
-
- DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob();
- assert(deopt_blob != NULL, "deoptimization blob must have been created");
- restore_live_registers(sasm);
-
- AddressLiteral dest(deopt_blob->unpack_with_reexecution());
- __ jump_to(dest, O0);
- __ delayed()->restore();
- }
- break;
-
- default:
- { __ set_info("unimplemented entry", dont_gc_arguments);
- __ save_frame(0);
- __ set((int)id, O1);
- __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), O1);
- __ should_not_reach_here();
- }
- break;
- }
- return oop_maps;
-}
-
-
-OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
- __ block_comment("generate_handle_exception");
-
- // Save registers, if required.
- OopMapSet* oop_maps = new OopMapSet();
- OopMap* oop_map = NULL;
- switch (id) {
- case forward_exception_id:
- // We're handling an exception in the context of a compiled frame.
- // The registers have been saved in the standard places. Perform
- // an exception lookup in the caller and dispatch to the handler
- // if found. Otherwise unwind and dispatch to the callers
- // exception handler.
- oop_map = generate_oop_map(sasm, true);
-
- // transfer the pending exception to the exception_oop
- __ ld_ptr(G2_thread, in_bytes(JavaThread::pending_exception_offset()), Oexception);
- __ ld_ptr(Oexception, 0, G0);
- __ st_ptr(G0, G2_thread, in_bytes(JavaThread::pending_exception_offset()));
- __ add(I7, frame::pc_return_offset, Oissuing_pc);
- break;
- case handle_exception_id:
- // At this point all registers MAY be live.
- oop_map = save_live_registers(sasm);
- __ mov(Oexception->after_save(), Oexception);
- __ mov(Oissuing_pc->after_save(), Oissuing_pc);
- break;
- case handle_exception_from_callee_id:
- // At this point all registers except exception oop (Oexception)
- // and exception pc (Oissuing_pc) are dead.
- oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
- sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
- __ save_frame_c1(frame_size_in_bytes);
- __ mov(Oexception->after_save(), Oexception);
- __ mov(Oissuing_pc->after_save(), Oissuing_pc);
- break;
- default: ShouldNotReachHere();
- }
-
- __ verify_not_null_oop(Oexception);
-
-#ifdef ASSERT
- // check that fields in JavaThread for exception oop and issuing pc are
- // empty before writing to them
- Label oop_empty;
- Register scratch = I7; // We can use I7 here because it's overwritten later anyway.
- __ ld_ptr(Address(G2_thread, JavaThread::exception_oop_offset()), scratch);
- __ br_null(scratch, false, Assembler::pt, oop_empty);
- __ delayed()->nop();
- __ stop("exception oop already set");
- __ bind(oop_empty);
-
- Label pc_empty;
- __ ld_ptr(Address(G2_thread, JavaThread::exception_pc_offset()), scratch);
- __ br_null(scratch, false, Assembler::pt, pc_empty);
- __ delayed()->nop();
- __ stop("exception pc already set");
- __ bind(pc_empty);
-#endif
-
- // save the exception and issuing pc in the thread
- __ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset()));
- __ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset()));
-
- // use the throwing pc as the return address to lookup (has bci & oop map)
- __ mov(Oissuing_pc, I7);
- __ sub(I7, frame::pc_return_offset, I7);
- int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc));
- oop_maps->add_gc_map(call_offset, oop_map);
-
- // Note: if nmethod has been deoptimized then regardless of
- // whether it had a handler or not we will deoptimize
- // by entering the deopt blob with a pending exception.
-
- // Restore the registers that were saved at the beginning, remove
- // the frame and jump to the exception handler.
- switch (id) {
- case forward_exception_id:
- case handle_exception_id:
- restore_live_registers(sasm);
- __ jmp(O0, 0);
- __ delayed()->restore();
- break;
- case handle_exception_from_callee_id:
- // Restore SP from L7 if the exception PC is a method handle call site.
- __ mov(O0, G5); // Save the target address.
- __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0);
- __ tst(L0); // Condition codes are preserved over the restore.
- __ restore();
-
- __ jmp(G5, 0); // jump to the exception handler
- __ delayed()->movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // Restore SP if required.
- break;
- default: ShouldNotReachHere();
- }
-
- return oop_maps;
-}
-
-
-#undef __
-
-const char *Runtime1::pd_name_for_address(address entry) {
- return "";
-}
diff --git a/src/hotspot/cpu/sparc/c1_globals_sparc.hpp b/src/hotspot/cpu/sparc/c1_globals_sparc.hpp
deleted file mode 100644
index b2b2032a197..00000000000
--- a/src/hotspot/cpu/sparc/c1_globals_sparc.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C1_GLOBALS_SPARC_HPP
-#define CPU_SPARC_C1_GLOBALS_SPARC_HPP
-
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
-
-// Sets the default values for platform dependent flags used by the client compiler.
-// (see c1_globals.hpp)
-
-#ifndef TIERED
-define_pd_global(bool, BackgroundCompilation, true );
-define_pd_global(bool, CICompileOSR, true );
-define_pd_global(bool, InlineIntrinsics, true );
-define_pd_global(bool, PreferInterpreterNativeStubs, false);
-define_pd_global(bool, ProfileTraps, false);
-define_pd_global(bool, UseOnStackReplacement, true );
-define_pd_global(bool, TieredCompilation, false);
-define_pd_global(intx, CompileThreshold, 1000 ); // Design center runs on 1.3.1
-
-define_pd_global(intx, OnStackReplacePercentage, 1400 );
-define_pd_global(bool, UseTLAB, true );
-define_pd_global(bool, ProfileInterpreter, false);
-define_pd_global(bool, ResizeTLAB, true );
-define_pd_global(uintx, ReservedCodeCacheSize, 32*M );
-define_pd_global(uintx, NonProfiledCodeHeapSize, 13*M );
-define_pd_global(uintx, ProfiledCodeHeapSize, 14*M );
-define_pd_global(uintx, NonNMethodCodeHeapSize, 5*M );
-define_pd_global(uintx, CodeCacheExpansionSize, 32*K );
-define_pd_global(uintx, CodeCacheMinBlockLength, 1);
-define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
-define_pd_global(size_t, MetaspaceSize, 12*M );
-define_pd_global(bool, NeverActAsServerClassMachine, true );
-define_pd_global(size_t, NewSizeThreadIncrease, 16*K );
-define_pd_global(uint64_t, MaxRAM, 1ULL*G);
-define_pd_global(uintx, InitialCodeCacheSize, 160*K);
-#endif // !TIERED
-
-define_pd_global(bool, UseTypeProfile, false);
-
-define_pd_global(bool, LIRFillDelaySlots, true );
-define_pd_global(bool, OptimizeSinglePrecision, false);
-define_pd_global(bool, CSEArrayLength, true );
-define_pd_global(bool, TwoOperandLIRForm, false);
-
-#endif // CPU_SPARC_C1_GLOBALS_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.cpp
deleted file mode 100644
index a9acd240334..00000000000
--- a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.cpp
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "asm/assembler.inline.hpp"
-#include "oops/arrayOop.hpp"
-#include "opto/c2_MacroAssembler.hpp"
-#include "opto/intrinsicnode.hpp"
-
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) /* nothing */
-#define STOP(error) stop(error)
-#else
-#define BLOCK_COMMENT(str) block_comment(str)
-#define STOP(error) block_comment(error); stop(error)
-#endif
-
-// Compress char[] to byte[] by compressing 16 bytes at once. Return 0 on failure.
-void C2_MacroAssembler::string_compress_16(Register src, Register dst, Register cnt, Register result,
- Register tmp1, Register tmp2, Register tmp3, Register tmp4,
- FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, Label& Ldone) {
- Label Lloop, Lslow;
- assert(UseVIS >= 3, "VIS3 is required");
- assert_different_registers(src, dst, cnt, tmp1, tmp2, tmp3, tmp4, result);
- assert_different_registers(ftmp1, ftmp2, ftmp3);
-
- // Check if cnt >= 8 (= 16 bytes)
- cmp(cnt, 8);
- br(Assembler::less, false, Assembler::pn, Lslow);
- delayed()->mov(cnt, result); // copy count
-
- // Check for 8-byte alignment of src and dst
- or3(src, dst, tmp1);
- andcc(tmp1, 7, G0);
- br(Assembler::notZero, false, Assembler::pn, Lslow);
- delayed()->nop();
-
- // Set mask for bshuffle instruction
- Register mask = tmp4;
- set(0x13579bdf, mask);
- bmask(mask, G0, G0);
-
- // Set mask to 0xff00 ff00 ff00 ff00 to check for non-latin1 characters
- Assembler::sethi(0xff00fc00, mask); // mask = 0x0000 0000 ff00 fc00
- add(mask, 0x300, mask); // mask = 0x0000 0000 ff00 ff00
- sllx(mask, 32, tmp1); // tmp1 = 0xff00 ff00 0000 0000
- or3(mask, tmp1, mask); // mask = 0xff00 ff00 ff00 ff00
-
- // Load first 8 bytes
- ldx(src, 0, tmp1);
-
- bind(Lloop);
- // Load next 8 bytes
- ldx(src, 8, tmp2);
-
- // Check for non-latin1 character by testing if the most significant byte of a char is set.
- // Although we have to move the data between integer and floating point registers, this is
- // still faster than the corresponding VIS instructions (ford/fand/fcmpd).
- or3(tmp1, tmp2, tmp3);
- btst(tmp3, mask);
- // annul zeroing if branch is not taken to preserve original count
- brx(Assembler::notZero, true, Assembler::pn, Ldone);
- delayed()->mov(G0, result); // 0 - failed
-
- // Move bytes into float register
- movxtod(tmp1, ftmp1);
- movxtod(tmp2, ftmp2);
-
- // Compress by copying one byte per char from ftmp1 and ftmp2 to ftmp3
- bshuffle(ftmp1, ftmp2, ftmp3);
- stf(FloatRegisterImpl::D, ftmp3, dst, 0);
-
- // Increment addresses and decrement count
- inc(src, 16);
- inc(dst, 8);
- dec(cnt, 8);
-
- cmp(cnt, 8);
- // annul LDX if branch is not taken to prevent access past end of string
- br(Assembler::greaterEqual, true, Assembler::pt, Lloop);
- delayed()->ldx(src, 0, tmp1);
-
- // Fallback to slow version
- bind(Lslow);
-}
-
-// Compress char[] to byte[]. Return 0 on failure.
-void C2_MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register result, Register tmp, Label& Ldone) {
- Label Lloop;
- assert_different_registers(src, dst, cnt, tmp, result);
-
- lduh(src, 0, tmp);
-
- bind(Lloop);
- inc(src, sizeof(jchar));
- cmp(tmp, 0xff);
- // annul zeroing if branch is not taken to preserve original count
- br(Assembler::greater, true, Assembler::pn, Ldone); // don't check xcc
- delayed()->mov(G0, result); // 0 - failed
- deccc(cnt);
- stb(tmp, dst, 0);
- inc(dst);
- // annul LDUH if branch is not taken to prevent access past end of string
- br(Assembler::notZero, true, Assembler::pt, Lloop);
- delayed()->lduh(src, 0, tmp); // hoisted
-}
-
-// Inflate byte[] to char[] by inflating 16 bytes at once.
-void C2_MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt, Register tmp,
- FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, FloatRegister ftmp4, Label& Ldone) {
- Label Lloop, Lslow;
- assert(UseVIS >= 3, "VIS3 is required");
- assert_different_registers(src, dst, cnt, tmp);
- assert_different_registers(ftmp1, ftmp2, ftmp3, ftmp4);
-
- // Check if cnt >= 8 (= 16 bytes)
- cmp(cnt, 8);
- br(Assembler::less, false, Assembler::pn, Lslow);
- delayed()->nop();
-
- // Check for 8-byte alignment of src and dst
- or3(src, dst, tmp);
- andcc(tmp, 7, G0);
- br(Assembler::notZero, false, Assembler::pn, Lslow);
- // Initialize float register to zero
- FloatRegister zerof = ftmp4;
- delayed()->fzero(FloatRegisterImpl::D, zerof);
-
- // Load first 8 bytes
- ldf(FloatRegisterImpl::D, src, 0, ftmp1);
-
- bind(Lloop);
- inc(src, 8);
- dec(cnt, 8);
-
- // Inflate the string by interleaving each byte from the source array
- // with a zero byte and storing the result in the destination array.
- fpmerge(zerof, ftmp1->successor(), ftmp2);
- stf(FloatRegisterImpl::D, ftmp2, dst, 8);
- fpmerge(zerof, ftmp1, ftmp3);
- stf(FloatRegisterImpl::D, ftmp3, dst, 0);
-
- inc(dst, 16);
-
- cmp(cnt, 8);
- // annul LDX if branch is not taken to prevent access past end of string
- br(Assembler::greaterEqual, true, Assembler::pt, Lloop);
- delayed()->ldf(FloatRegisterImpl::D, src, 0, ftmp1);
-
- // Fallback to slow version
- bind(Lslow);
-}
-
-// Inflate byte[] to char[].
-void C2_MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp, Label& Ldone) {
- Label Loop;
- assert_different_registers(src, dst, cnt, tmp);
-
- ldub(src, 0, tmp);
- bind(Loop);
- inc(src);
- deccc(cnt);
- sth(tmp, dst, 0);
- inc(dst, sizeof(jchar));
- // annul LDUB if branch is not taken to prevent access past end of string
- br(Assembler::notZero, true, Assembler::pt, Loop);
- delayed()->ldub(src, 0, tmp); // hoisted
-}
-
-void C2_MacroAssembler::string_compare(Register str1, Register str2,
- Register cnt1, Register cnt2,
- Register tmp1, Register tmp2,
- Register result, int ae) {
- Label Ldone, Lloop;
- assert_different_registers(str1, str2, cnt1, cnt2, tmp1, result);
- int stride1, stride2;
-
- // Note: Making use of the fact that compareTo(a, b) == -compareTo(b, a)
- // we interchange str1 and str2 in the UL case and negate the result.
- // Like this, str1 is always latin1 encoded, expect for the UU case.
-
- if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) {
- srl(cnt2, 1, cnt2);
- }
-
- // See if the lengths are different, and calculate min in cnt1.
- // Save diff in case we need it for a tie-breaker.
- Label Lskip;
- Register diff = tmp1;
- subcc(cnt1, cnt2, diff);
- br(Assembler::greater, true, Assembler::pt, Lskip);
- // cnt2 is shorter, so use its count:
- delayed()->mov(cnt2, cnt1);
- bind(Lskip);
-
- // Rename registers
- Register limit1 = cnt1;
- Register limit2 = limit1;
- Register chr1 = result;
- Register chr2 = cnt2;
- if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) {
- // We need an additional register to keep track of two limits
- assert_different_registers(str1, str2, cnt1, cnt2, tmp1, tmp2, result);
- limit2 = tmp2;
- }
-
- // Is the minimum length zero?
- cmp(limit1, (int)0); // use cast to resolve overloading ambiguity
- br(Assembler::equal, true, Assembler::pn, Ldone);
- // result is difference in lengths
- if (ae == StrIntrinsicNode::UU) {
- delayed()->sra(diff, 1, result); // Divide by 2 to get number of chars
- } else {
- delayed()->mov(diff, result);
- }
-
- // Load first characters
- if (ae == StrIntrinsicNode::LL) {
- stride1 = stride2 = sizeof(jbyte);
- ldub(str1, 0, chr1);
- ldub(str2, 0, chr2);
- } else if (ae == StrIntrinsicNode::UU) {
- stride1 = stride2 = sizeof(jchar);
- lduh(str1, 0, chr1);
- lduh(str2, 0, chr2);
- } else {
- stride1 = sizeof(jbyte);
- stride2 = sizeof(jchar);
- ldub(str1, 0, chr1);
- lduh(str2, 0, chr2);
- }
-
- // Compare first characters
- subcc(chr1, chr2, chr1);
- br(Assembler::notZero, false, Assembler::pt, Ldone);
- assert(chr1 == result, "result must be pre-placed");
- delayed()->nop();
-
- // Check if the strings start at same location
- cmp(str1, str2);
- brx(Assembler::equal, true, Assembler::pn, Ldone);
- delayed()->mov(G0, result); // result is zero
-
- // We have no guarantee that on 64 bit the higher half of limit is 0
- signx(limit1);
-
- // Get limit
- if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) {
- sll(limit1, 1, limit2);
- subcc(limit2, stride2, chr2);
- }
- subcc(limit1, stride1, chr1);
- br(Assembler::zero, true, Assembler::pn, Ldone);
- // result is difference in lengths
- if (ae == StrIntrinsicNode::UU) {
- delayed()->sra(diff, 1, result); // Divide by 2 to get number of chars
- } else {
- delayed()->mov(diff, result);
- }
-
- // Shift str1 and str2 to the end of the arrays, negate limit
- add(str1, limit1, str1);
- add(str2, limit2, str2);
- neg(chr1, limit1); // limit1 = -(limit1-stride1)
- if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) {
- neg(chr2, limit2); // limit2 = -(limit2-stride2)
- }
-
- // Compare the rest of the characters
- load_sized_value(Address(str1, limit1), chr1, (ae == StrIntrinsicNode::UU) ? 2 : 1, false);
-
- bind(Lloop);
- load_sized_value(Address(str2, limit2), chr2, (ae == StrIntrinsicNode::LL) ? 1 : 2, false);
-
- subcc(chr1, chr2, chr1);
- br(Assembler::notZero, false, Assembler::pt, Ldone);
- assert(chr1 == result, "result must be pre-placed");
- delayed()->inccc(limit1, stride1);
- if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) {
- inccc(limit2, stride2);
- }
-
- // annul LDUB if branch is not taken to prevent access past end of string
- br(Assembler::notZero, true, Assembler::pt, Lloop);
- delayed()->load_sized_value(Address(str1, limit1), chr1, (ae == StrIntrinsicNode::UU) ? 2 : 1, false);
-
- // If strings are equal up to min length, return the length difference.
- if (ae == StrIntrinsicNode::UU) {
- // Divide by 2 to get number of chars
- sra(diff, 1, result);
- } else {
- mov(diff, result);
- }
-
- // Otherwise, return the difference between the first mismatched chars.
- bind(Ldone);
- if(ae == StrIntrinsicNode::UL) {
- // Negate result (see note above)
- neg(result);
- }
-}
-
-void C2_MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary2,
- Register limit, Register tmp, Register result, bool is_byte) {
- Label Ldone, Lloop, Lremaining;
- assert_different_registers(ary1, ary2, limit, tmp, result);
-
- int length_offset = arrayOopDesc::length_offset_in_bytes();
- int base_offset = arrayOopDesc::base_offset_in_bytes(is_byte ? T_BYTE : T_CHAR);
- assert(base_offset % 8 == 0, "Base offset must be 8-byte aligned");
-
- if (is_array_equ) {
- // return true if the same array
- cmp(ary1, ary2);
- brx(Assembler::equal, true, Assembler::pn, Ldone);
- delayed()->mov(1, result); // equal
-
- br_null(ary1, true, Assembler::pn, Ldone);
- delayed()->clr(result); // not equal
-
- br_null(ary2, true, Assembler::pn, Ldone);
- delayed()->clr(result); // not equal
-
- // load the lengths of arrays
- ld(Address(ary1, length_offset), limit);
- ld(Address(ary2, length_offset), tmp);
-
- // return false if the two arrays are not equal length
- cmp(limit, tmp);
- br(Assembler::notEqual, true, Assembler::pn, Ldone);
- delayed()->clr(result); // not equal
- }
-
- cmp_zero_and_br(Assembler::zero, limit, Ldone, true, Assembler::pn);
- delayed()->mov(1, result); // zero-length arrays are equal
-
- if (is_array_equ) {
- // load array addresses
- add(ary1, base_offset, ary1);
- add(ary2, base_offset, ary2);
- // set byte count
- if (!is_byte) {
- sll(limit, exact_log2(sizeof(jchar)), limit);
- }
- } else {
- // We have no guarantee that on 64 bit the higher half of limit is 0
- signx(limit);
- }
-
-#ifdef ASSERT
- // Sanity check for doubleword (8-byte) alignment of ary1 and ary2.
- // Guaranteed on 64-bit systems (see arrayOopDesc::header_size_in_bytes()).
- Label Laligned;
- or3(ary1, ary2, tmp);
- andcc(tmp, 7, tmp);
- br_null_short(tmp, Assembler::pn, Laligned);
- STOP("First array element is not 8-byte aligned.");
- should_not_reach_here();
- bind(Laligned);
-#endif
-
- // Shift ary1 and ary2 to the end of the arrays, negate limit
- add(ary1, limit, ary1);
- add(ary2, limit, ary2);
- neg(limit, limit);
-
- // MAIN LOOP
- // Load and compare array elements of size 'byte_width' until the elements are not
- // equal or we reached the end of the arrays. If the size of the arrays is not a
- // multiple of 'byte_width', we simply read over the end of the array, bail out and
- // compare the remaining bytes below by skipping the garbage bytes.
- ldx(ary1, limit, result);
- bind(Lloop);
- ldx(ary2, limit, tmp);
- inccc(limit, 8);
- // Bail out if we reached the end (but still do the comparison)
- br(Assembler::positive, false, Assembler::pn, Lremaining);
- delayed()->cmp(result, tmp);
- // Check equality of elements
- brx(Assembler::equal, false, Assembler::pt, target(Lloop));
- delayed()->ldx(ary1, limit, result);
-
- ba(Ldone);
- delayed()->clr(result); // not equal
-
- // TAIL COMPARISON
- // We got here because we reached the end of the arrays. 'limit' is the number of
- // garbage bytes we may have compared by reading over the end of the arrays. Shift
- // out the garbage and compare the remaining elements.
- bind(Lremaining);
- // Optimistic shortcut: elements potentially including garbage are equal
- brx(Assembler::equal, true, Assembler::pt, target(Ldone));
- delayed()->mov(1, result); // equal
- // Shift 'limit' bytes to the right and compare
- sll(limit, 3, limit); // bytes to bits
- srlx(result, limit, result);
- srlx(tmp, limit, tmp);
- cmp(result, tmp);
- clr(result);
- movcc(Assembler::equal, false, xcc, 1, result);
-
- bind(Ldone);
-}
-
-void C2_MacroAssembler::has_negatives(Register inp, Register size, Register result, Register t2, Register t3, Register t4, Register t5) {
-
- // test for negative bytes in input string of a given size
- // result 1 if found, 0 otherwise.
-
- Label Lcore, Ltail, Lreturn, Lcore_rpt;
-
- assert_different_registers(inp, size, t2, t3, t4, t5, result);
-
- Register i = result; // result used as integer index i until very end
- Register lmask = t2; // t2 is aliased to lmask
-
- // INITIALIZATION
- // ===========================================================
- // initialize highbits mask -> lmask = 0x8080808080808080 (8B/64b)
- // compute unaligned offset -> i
- // compute core end index -> t5
- Assembler::sethi(0x80808000, t2); //! sethi macro fails to emit optimal
- add(t2, 0x80, t2);
- sllx(t2, 32, t3);
- or3(t3, t2, lmask); // 0x8080808080808080 -> lmask
- sra(size,0,size);
- andcc(inp, 0x7, i); // unaligned offset -> i
- br(Assembler::zero, true, Assembler::pn, Lcore); // starts 8B aligned?
- delayed()->add(size, -8, t5); // (annuled) core end index -> t5
-
- // ===========================================================
-
- // UNALIGNED HEAD
- // ===========================================================
- // * unaligned head handling: grab aligned 8B containing unaligned inp(ut)
- // * obliterate (ignore) bytes outside string by shifting off reg ends
- // * compare with bitmask, short circuit return true if one or more high
- // bits set.
- cmp(size, 0);
- br(Assembler::zero, true, Assembler::pn, Lreturn); // short-circuit?
- delayed()->mov(0,result); // annuled so i not clobbered for following
- neg(i, t4);
- add(i, size, t5);
- ldx(inp, t4, t3); // raw aligned 8B containing unaligned head -> t3
- mov(8, t4);
- sub(t4, t5, t4);
- sra(t4, 31, t5);
- andn(t4, t5, t5);
- add(i, t5, t4);
- sll(t5, 3, t5);
- sll(t4, 3, t4); // # bits to shift right, left -> t5,t4
- srlx(t3, t5, t3);
- sllx(t3, t4, t3); // bytes outside string in 8B header obliterated -> t3
- andcc(lmask, t3, G0);
- brx(Assembler::notZero, true, Assembler::pn, Lreturn); // short circuit?
- delayed()->mov(1,result); // annuled so i not clobbered for following
- add(size, -8, t5); // core end index -> t5
- mov(8, t4);
- sub(t4, i, i); // # bytes examined in unalgn head (<8) -> i
- // ===========================================================
-
- // ALIGNED CORE
- // ===========================================================
- // * iterate index i over aligned 8B sections of core, comparing with
- // bitmask, short circuit return true if one or more high bits set
- // t5 contains core end index/loop limit which is the index
- // of the MSB of last (unaligned) 8B fully contained in the string.
- // inp contains address of first byte in string/array
- // lmask contains 8B high bit mask for comparison
- // i contains next index to be processed (adr. inp+i is on 8B boundary)
- bind(Lcore);
- cmp_and_br_short(i, t5, Assembler::greater, Assembler::pn, Ltail);
- bind(Lcore_rpt);
- ldx(inp, i, t3);
- andcc(t3, lmask, G0);
- brx(Assembler::notZero, true, Assembler::pn, Lreturn);
- delayed()->mov(1, result); // annuled so i not clobbered for following
- add(i, 8, i);
- cmp_and_br_short(i, t5, Assembler::lessEqual, Assembler::pn, Lcore_rpt);
- // ===========================================================
-
- // ALIGNED TAIL (<8B)
- // ===========================================================
- // handle aligned tail of 7B or less as complete 8B, obliterating end of
- // string bytes by shifting them off end, compare what's left with bitmask
- // inp contains address of first byte in string/array
- // lmask contains 8B high bit mask for comparison
- // i contains next index to be processed (adr. inp+i is on 8B boundary)
- bind(Ltail);
- subcc(size, i, t4); // # of remaining bytes in string -> t4
- // return 0 if no more remaining bytes
- br(Assembler::lessEqual, true, Assembler::pn, Lreturn);
- delayed()->mov(0, result); // annuled so i not clobbered for following
- ldx(inp, i, t3); // load final 8B (aligned) containing tail -> t3
- mov(8, t5);
- sub(t5, t4, t4);
- mov(0, result); // ** i clobbered at this point
- sll(t4, 3, t4); // bits beyond end of string -> t4
- srlx(t3, t4, t3); // bytes beyond end now obliterated -> t3
- andcc(lmask, t3, G0);
- movcc(Assembler::notZero, false, xcc, 1, result);
- bind(Lreturn);
-}
-
diff --git a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.hpp
deleted file mode 100644
index de14f334696..00000000000
--- a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C2_MACROASSEMBLER_SPARC_HPP
-#define CPU_SPARC_C2_MACROASSEMBLER_SPARC_HPP
-
-// C2_MacroAssembler contains high-level macros for C2
-
- public:
- // Compress char[] to byte[] by compressing 16 bytes at once. Return 0 on failure.
- void string_compress_16(Register src, Register dst, Register cnt, Register result,
- Register tmp1, Register tmp2, Register tmp3, Register tmp4,
- FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, Label& Ldone);
-
- // Compress char[] to byte[]. Return 0 on failure.
- void string_compress(Register src, Register dst, Register cnt, Register tmp, Register result, Label& Ldone);
-
- // Inflate byte[] to char[] by inflating 16 bytes at once.
- void string_inflate_16(Register src, Register dst, Register cnt, Register tmp,
- FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, FloatRegister ftmp4, Label& Ldone);
-
- // Inflate byte[] to char[].
- void string_inflate(Register src, Register dst, Register cnt, Register tmp, Label& Ldone);
-
- void string_compare(Register str1, Register str2,
- Register cnt1, Register cnt2,
- Register tmp1, Register tmp2,
- Register result, int ae);
-
- void array_equals(bool is_array_equ, Register ary1, Register ary2,
- Register limit, Register tmp, Register result, bool is_byte);
- // test for negative bytes in input string of a given size, result 0 if none
- void has_negatives(Register inp, Register size, Register result,
- Register t2, Register t3, Register t4,
- Register t5);
-
-#endif // CPU_SPARC_C2_MACROASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c2_globals_sparc.hpp b/src/hotspot/cpu/sparc/c2_globals_sparc.hpp
deleted file mode 100644
index 6fcb3f481e8..00000000000
--- a/src/hotspot/cpu/sparc/c2_globals_sparc.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_C2_GLOBALS_SPARC_HPP
-#define CPU_SPARC_C2_GLOBALS_SPARC_HPP
-
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
-
-// Sets the default values for platform dependent flags used by the server compiler.
-// (see c2_globals.hpp). Alpha-sorted.
-
-define_pd_global(bool, BackgroundCompilation, true);
-define_pd_global(bool, CICompileOSR, true);
-define_pd_global(bool, InlineIntrinsics, true);
-define_pd_global(bool, PreferInterpreterNativeStubs, false);
-define_pd_global(bool, ProfileTraps, true);
-define_pd_global(bool, UseOnStackReplacement, true);
-define_pd_global(bool, ProfileInterpreter, true);
-define_pd_global(bool, TieredCompilation, trueInTiered);
-define_pd_global(intx, CompileThreshold, 10000);
-
-define_pd_global(intx, OnStackReplacePercentage, 140);
-define_pd_global(intx, ConditionalMoveLimit, 4);
-define_pd_global(intx, FLOATPRESSURE, 52); // C2 on V9 gets to use all the float/double registers
-define_pd_global(intx, FreqInlineSize, 175);
-define_pd_global(intx, INTPRESSURE, 48); // large register set
-define_pd_global(intx, InteriorEntryAlignment, 16); // = CodeEntryAlignment
-define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
-define_pd_global(intx, RegisterCostAreaRatio, 12000);
-define_pd_global(bool, UseTLAB, true);
-define_pd_global(bool, ResizeTLAB, true);
-define_pd_global(intx, LoopUnrollLimit, 60); // Design center runs on 1.3.1
-define_pd_global(intx, LoopPercentProfileLimit, 10);
-define_pd_global(intx, MinJumpTableSize, 5);
-
-// Peephole and CISC spilling both break the graph, and so makes the
-// scheduler sick.
-define_pd_global(bool, OptoPeephole, false);
-define_pd_global(bool, UseCISCSpill, false);
-define_pd_global(bool, OptoBundling, false);
-define_pd_global(bool, OptoScheduling, true);
-define_pd_global(bool, OptoRegScheduling, false);
-define_pd_global(bool, SuperWordLoopUnrollAnalysis, false);
-define_pd_global(bool, IdealizeClearArrayNode, true);
-
-// We need to make sure that all generated code is within
-// 2 gigs of the libjvm.so runtime routines so we can use
-// the faster "call" instruction rather than the expensive
-// sequence of instructions to load a 64 bit pointer.
-//
-// InitialCodeCacheSize derived from specjbb2000 run.
-define_pd_global(uintx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize
-define_pd_global(uintx, ReservedCodeCacheSize, 48*M);
-define_pd_global(uintx, NonProfiledCodeHeapSize, 21*M);
-define_pd_global(uintx, ProfiledCodeHeapSize, 22*M);
-define_pd_global(uintx, NonNMethodCodeHeapSize, 5*M );
-define_pd_global(uintx, CodeCacheExpansionSize, 64*K);
-
-// Ergonomics related flags
-define_pd_global(uint64_t,MaxRAM, 128ULL*G);
-define_pd_global(uintx, CodeCacheMinBlockLength, 6);
-define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
-
-define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed on sparc.
-
-// Heap related flags
-define_pd_global(size_t, MetaspaceSize, ScaleForWordSize(16*M));
-
-// Ergonomics related flags
-define_pd_global(bool, NeverActAsServerClassMachine, false);
-
-#endif // CPU_SPARC_C2_GLOBALS_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/c2_init_sparc.cpp b/src/hotspot/cpu/sparc/c2_init_sparc.cpp
deleted file mode 100644
index b4b3bbd45b9..00000000000
--- a/src/hotspot/cpu/sparc/c2_init_sparc.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "opto/compile.hpp"
-#include "opto/node.hpp"
-
-// processor dependent initialization for sparc
-
-void Compile::pd_compiler2_init() {
- guarantee(CodeEntryAlignment >= InteriorEntryAlignment, "" );
-}
diff --git a/src/hotspot/cpu/sparc/codeBuffer_sparc.hpp b/src/hotspot/cpu/sparc/codeBuffer_sparc.hpp
deleted file mode 100644
index 14011d68f1c..00000000000
--- a/src/hotspot/cpu/sparc/codeBuffer_sparc.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_CODEBUFFER_SPARC_HPP
-#define CPU_SPARC_CODEBUFFER_SPARC_HPP
-
-private:
- void pd_initialize() {}
-
-public:
- void flush_bundle(bool start_new_bundle) {}
-
-#endif // CPU_SPARC_CODEBUFFER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/compiledIC_sparc.cpp b/src/hotspot/cpu/sparc/compiledIC_sparc.cpp
deleted file mode 100644
index b48f257cf50..00000000000
--- a/src/hotspot/cpu/sparc/compiledIC_sparc.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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/compiledIC.hpp"
-#include "code/icBuffer.hpp"
-#include "code/nmethod.hpp"
-#include "memory/resourceArea.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/safepoint.hpp"
-#ifdef COMPILER2
-#include "opto/matcher.hpp"
-#endif
-
-// ----------------------------------------------------------------------------
-
-#define __ _masm.
-address CompiledStaticCall::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), G5
- // jmp -1
-
- if (mark == NULL) {
- mark = cbuf.insts_mark(); // Get mark within main instrs section.
- }
-
- MacroAssembler _masm(&cbuf);
-
- address base = __ start_a_stub(to_interp_stub_size());
- if (base == NULL) {
- return NULL; // CodeBuffer::expand failed.
- }
-
- // Static stub relocation stores the instruction address of the call.
- __ relocate(static_stub_Relocation::spec(mark));
-
- __ set_metadata(NULL, as_Register(Matcher::inline_cache_reg_encode()));
-
- __ set_inst_mark();
- AddressLiteral addrlit(-1);
- __ JUMP(addrlit, G3, 0);
-
- __ delayed()->nop();
-
- assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size");
-
- // Update current stubs pointer and restore code_end.
- __ end_a_stub();
- return base;
-}
-#undef __
-
-int CompiledStaticCall::to_trampoline_stub_size() {
- // SPARC doesn't use trampolines.
- return 0;
-}
-
-int CompiledStaticCall::to_interp_stub_size() {
- // This doesn't need to be accurate but it must be larger or equal to
- // the real size of the stub.
- return (NativeMovConstReg::instruction_size + // sethi/setlo;
- NativeJump::instruction_size); // sethi; jmp; nop
-}
-
-// Relocation entries for call stub, compiled java to interpreter.
-int CompiledStaticCall::reloc_to_interp_stub() {
- return 10; // 4 in emit_java_to_interp + 1 in Java_Static_Call
-}
-
-void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) {
- address stub = find_stub(/*is_aot*/ false);
- guarantee(stub != NULL, "stub not found");
-
- if (TraceICs) {
- ResourceMark rm;
- tty->print_cr("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());
- verify_mt_safe(callee, entry, method_holder, jump);
-
- // Update stub.
- method_holder->set_data((intptr_t)callee());
- jump->set_jump_destination(entry);
-
- // Update jump to call.
- set_destination_mt_safe(stub);
-}
-
-void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
- // Reset stub.
- address stub = static_stub->addr();
- assert(stub != NULL, "stub not found");
- assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
- // Creation also verifies the object.
- NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
- NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
- method_holder->set_data(0);
- jump->set_jump_destination((address)-1);
-}
-
-//-----------------------------------------------------------------------------
-// Non-product mode code
-#ifndef PRODUCT
-
-void CompiledDirectStaticCall::verify() {
- // Verify call.
- _call->verify();
- _call->verify_alignment();
-
- // Verify stub.
- address stub = find_stub(/*is_aot*/ false);
- assert(stub != NULL, "no stub found for static call");
- // Creation also verifies the object.
- NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
- NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
-
- // Verify state.
- assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
-}
-
-#endif // !PRODUCT
diff --git a/src/hotspot/cpu/sparc/copy_sparc.hpp b/src/hotspot/cpu/sparc/copy_sparc.hpp
deleted file mode 100644
index 68f2f600c4b..00000000000
--- a/src/hotspot/cpu/sparc/copy_sparc.hpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_COPY_SPARC_HPP
-#define CPU_SPARC_COPY_SPARC_HPP
-
-// Inline functions for memory copy and fill.
-
-static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
- (void)memmove(to, from, count * HeapWordSize);
-}
-
-static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
- switch (count) {
- case 8: to[7] = from[7];
- case 7: to[6] = from[6];
- case 6: to[5] = from[5];
- case 5: to[4] = from[4];
- case 4: to[3] = from[3];
- case 3: to[2] = from[2];
- case 2: to[1] = from[1];
- case 1: to[0] = from[0];
- case 0: break;
- default: (void)memcpy(to, from, count * HeapWordSize);
- break;
- }
-}
-
-static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) {
- switch (count) {
- case 8: to[7] = from[7];
- case 7: to[6] = from[6];
- case 6: to[5] = from[5];
- case 5: to[4] = from[4];
- case 4: to[3] = from[3];
- case 3: to[2] = from[2];
- case 2: to[1] = from[1];
- case 1: to[0] = from[0];
- case 0: break;
- default: while (count-- > 0) {
- *to++ = *from++;
- }
- break;
- }
-}
-
-static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
- (void)memmove(to, from, count * HeapWordSize);
-}
-
-static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
- pd_disjoint_words(from, to, count);
-}
-
-static void pd_conjoint_bytes(const void* from, void* to, size_t count) {
- (void)memmove(to, from, count);
-}
-
-static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) {
- (void)memmove(to, from, count);
-}
-
-static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) {
- if (from > to) {
- while (count-- > 0) {
- // Copy forwards
- *to++ = *from++;
- }
- } else {
- from += count - 1;
- to += count - 1;
- while (count-- > 0) {
- // Copy backwards
- *to-- = *from--;
- }
- }
-}
-
-static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) {
- if (from > to) {
- while (count-- > 0) {
- // Copy forwards
- *to++ = *from++;
- }
- } else {
- from += count - 1;
- to += count - 1;
- while (count-- > 0) {
- // Copy backwards
- *to-- = *from--;
- }
- }
-}
-
-static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) {
- assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size");
- pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count);
-}
-
-static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) {
- // Do better than this: inline memmove body NEEDS CLEANUP
- if (from > to) {
- while (count-- > 0) {
- // Copy forwards
- *to++ = *from++;
- }
- } else {
- from += count - 1;
- to += count - 1;
- while (count-- > 0) {
- // Copy backwards
- *to-- = *from--;
- }
- }
-}
-
-static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) {
- pd_conjoint_bytes_atomic(from, to, count);
-}
-
-static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) {
- pd_conjoint_jshorts_atomic((const jshort*)from, (jshort*)to, count);
-}
-
-static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) {
- pd_conjoint_jints_atomic((const jint*)from, (jint*)to, count);
-}
-
-static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) {
- pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count);
-}
-
-static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) {
- pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count);
-}
-
-static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) {
- guarantee(mask_bits((uintptr_t)tohw, right_n_bits(LogBytesPerLong)) == 0,
- "unaligned fill words");
- julong* to = (julong*)tohw;
- julong v = ((julong)value << 32) | value;
- while (count-- > 0) {
- *to++ = v;
- }
-}
-
-typedef void (*_zero_Fn)(HeapWord* to, size_t count);
-
-// Only used for heap objects, so align_object_offset.
-// All other platforms pd_fill_to_aligned_words simply calls pd_fill_to_words, don't
-// know why this one is different.
-static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) {
- assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation");
-
- if (value == 0 && UseBlockZeroing &&
- (count > (size_t)(BlockZeroingLowLimit >> LogHeapWordSize))) {
- // Call it only when block zeroing is used
- ((_zero_Fn)StubRoutines::zero_aligned_words())(tohw, count);
- } else {
- julong* to = (julong*)tohw;
- julong v = ((julong)value << 32) | value;
- // If count is odd, odd will be equal to 1 on 32-bit platform
- // and be equal to 0 on 64-bit platform.
- size_t odd = count % (BytesPerLong / HeapWordSize) ;
-
- size_t aligned_count = align_object_offset(count - odd) / HeapWordsPerLong;
- julong* end = ((julong*)tohw) + aligned_count - 1;
- while (to <= end) {
- DEBUG_ONLY(count -= BytesPerLong / HeapWordSize ;)
- *to++ = v;
- }
- assert(count == odd, "bad bounds on loop filling to aligned words");
- if (odd) {
- *((juint*)to) = value;
-
- }
- }
-}
-
-static void pd_fill_to_bytes(void* to, size_t count, jubyte value) {
- (void)memset(to, value, count);
-}
-
-static void pd_zero_to_words(HeapWord* tohw, size_t count) {
- pd_fill_to_words(tohw, count, 0);
-}
-
-static void pd_zero_to_bytes(void* to, size_t count) {
- (void)memset(to, 0, count);
-}
-
-#endif // CPU_SPARC_COPY_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/depChecker_sparc.cpp b/src/hotspot/cpu/sparc/depChecker_sparc.cpp
deleted file mode 100644
index abb0243a2f6..00000000000
--- a/src/hotspot/cpu/sparc/depChecker_sparc.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "compiler/disassembler.hpp"
-#include "depChecker_sparc.hpp"
-
-// Nothing to do on Sparc
diff --git a/src/hotspot/cpu/sparc/depChecker_sparc.hpp b/src/hotspot/cpu/sparc/depChecker_sparc.hpp
deleted file mode 100644
index c17c5e1d7f4..00000000000
--- a/src/hotspot/cpu/sparc/depChecker_sparc.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_DEPCHECKER_SPARC_HPP
-#define CPU_SPARC_DEPCHECKER_SPARC_HPP
-
-// Nothing to do on Sparc
-
-#endif // CPU_SPARC_DEPCHECKER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/disassembler_sparc.hpp b/src/hotspot/cpu/sparc/disassembler_sparc.hpp
deleted file mode 100644
index 9d3a8e464f0..00000000000
--- a/src/hotspot/cpu/sparc/disassembler_sparc.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_DISASSEMBLER_SPARC_HPP
-#define CPU_SPARC_DISASSEMBLER_SPARC_HPP
-
- static int pd_instruction_alignment() {
- return sizeof(int);
- }
-
- static const char* pd_cpu_opts() {
- return "v9only";
- }
-
- // Returns address of n-th instruction preceding addr,
- // NULL if no preceding instruction can be found.
- // With SPARC being a RISC architecture, this always is BytesPerInstWord
- // It might be beneficial to check "is_readable" as we do on ppc and s390.
- static address find_prev_instr(address addr, int n_instr) {
- return addr - BytesPerInstWord*n_instr;
- }
-
- // special-case instruction decoding.
- // There may be cases where the binutils disassembler doesn't do
- // the perfect job. In those cases, decode_instruction0 may kick in
- // and do it right.
- // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)"
- static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) {
- return here;
- }
-
- // platform-specific instruction annotations (like value of loaded constants)
- static void annotate(address pc, outputStream* st) { };
-
-#endif // CPU_SPARC_DISASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/frame_sparc.cpp b/src/hotspot/cpu/sparc/frame_sparc.cpp
deleted file mode 100644
index 4a394142b5a..00000000000
--- a/src/hotspot/cpu/sparc/frame_sparc.cpp
+++ /dev/null
@@ -1,822 +0,0 @@
-/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "code/codeCache.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/resourceArea.hpp"
-#include "memory/universe.hpp"
-#include "oops/markWord.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/methodHandles.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/javaCalls.hpp"
-#include "runtime/monitorChunk.hpp"
-#include "runtime/signature.hpp"
-#include "runtime/stubCodeGenerator.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "vmreg_sparc.inline.hpp"
-#ifdef COMPILER1
-#include "c1/c1_Runtime1.hpp"
-#include "runtime/vframeArray.hpp"
-#endif
-
-void RegisterMap::pd_clear() {
- if (_thread->has_last_Java_frame()) {
- frame fr = _thread->last_frame();
- _window = fr.sp();
- } else {
- _window = NULL;
- }
- _younger_window = NULL;
-}
-
-
-// Unified register numbering scheme: each 32-bits counts as a register
-// number, so all the V9 registers take 2 slots.
-const static int R_L_nums[] = {0+040,2+040,4+040,6+040,8+040,10+040,12+040,14+040};
-const static int R_I_nums[] = {0+060,2+060,4+060,6+060,8+060,10+060,12+060,14+060};
-const static int R_O_nums[] = {0+020,2+020,4+020,6+020,8+020,10+020,12+020,14+020};
-const static int R_G_nums[] = {0+000,2+000,4+000,6+000,8+000,10+000,12+000,14+000};
-static RegisterMap::LocationValidType bad_mask = 0;
-static RegisterMap::LocationValidType R_LIO_mask = 0;
-static bool register_map_inited = false;
-
-static void register_map_init() {
- if (!register_map_inited) {
- register_map_inited = true;
- int i;
- for (i = 0; i < 8; i++) {
- assert(R_L_nums[i] < RegisterMap::location_valid_type_size, "in first chunk");
- assert(R_I_nums[i] < RegisterMap::location_valid_type_size, "in first chunk");
- assert(R_O_nums[i] < RegisterMap::location_valid_type_size, "in first chunk");
- assert(R_G_nums[i] < RegisterMap::location_valid_type_size, "in first chunk");
- }
-
- bad_mask |= (1LL << R_O_nums[6]); // SP
- bad_mask |= (1LL << R_O_nums[7]); // cPC
- bad_mask |= (1LL << R_I_nums[6]); // FP
- bad_mask |= (1LL << R_I_nums[7]); // rPC
- bad_mask |= (1LL << R_G_nums[2]); // TLS
- bad_mask |= (1LL << R_G_nums[7]); // reserved by libthread
-
- for (i = 0; i < 8; i++) {
- R_LIO_mask |= (1LL << R_L_nums[i]);
- R_LIO_mask |= (1LL << R_I_nums[i]);
- R_LIO_mask |= (1LL << R_O_nums[i]);
- }
- }
-}
-
-
-address RegisterMap::pd_location(VMReg regname) const {
- register_map_init();
-
- assert(regname->is_reg(), "sanity check");
- // Only the GPRs get handled this way
- if( !regname->is_Register())
- return NULL;
-
- // don't talk about bad registers
- if ((bad_mask & ((LocationValidType)1 << regname->value())) != 0) {
- return NULL;
- }
-
- // Convert to a GPR
- Register reg;
- int second_word = 0;
- // 32-bit registers for in, out and local
- if (!regname->is_concrete()) {
- // HMM ought to return NULL for any non-concrete (odd) vmreg
- // this all tied up in the fact we put out double oopMaps for
- // register locations. When that is fixed we'd will return NULL
- // (or assert here).
- reg = regname->prev()->as_Register();
- second_word = sizeof(jint);
- } else {
- reg = regname->as_Register();
- }
- if (reg->is_out()) {
- return _younger_window == NULL ? NULL :
- second_word + (address)&_younger_window[reg->after_save()->sp_offset_in_saved_window()];
- }
- if (reg->is_local() || reg->is_in()) {
- assert(_window != NULL, "Window should be available");
- return second_word + (address)&_window[reg->sp_offset_in_saved_window()];
- }
- // Only the window'd GPRs get handled this way; not the globals.
- return NULL;
-}
-
-
-#ifdef ASSERT
-void RegisterMap::check_location_valid() {
- register_map_init();
- assert((_location_valid[0] & bad_mask) == 0, "cannot have special locations for SP,FP,TLS,etc.");
-}
-#endif
-
-// We are shifting windows. That means we are moving all %i to %o,
-// getting rid of all current %l, and keeping all %g. This is only
-// complicated if any of the location pointers for these are valid.
-// The normal case is that everything is in its standard register window
-// home, and _location_valid[0] is zero. In that case, this routine
-// does exactly nothing.
-void RegisterMap::shift_individual_registers() {
- if (!update_map()) return; // this only applies to maps with locations
- register_map_init();
- check_location_valid();
-
- LocationValidType lv = _location_valid[0];
- LocationValidType lv0 = lv;
-
- lv &= ~R_LIO_mask; // clear %l, %o, %i regs
-
- // if we cleared some non-%g locations, we may have to do some shifting
- if (lv != lv0) {
- // copy %i0-%i5 to %o0-%o5, if they have special locations
- // This can happen in within stubs which spill argument registers
- // around a dynamic link operation, such as resolve_opt_virtual_call.
- for (int i = 0; i < 8; i++) {
- if (lv0 & (1LL << R_I_nums[i])) {
- _location[R_O_nums[i]] = _location[R_I_nums[i]];
- lv |= (1LL << R_O_nums[i]);
- }
- }
- }
-
- _location_valid[0] = lv;
- check_location_valid();
-}
-
-bool frame::safe_for_sender(JavaThread *thread) {
-
- address _SP = (address) sp();
- address _FP = (address) fp();
- address _UNEXTENDED_SP = (address) unextended_sp();
-
- // consider stack guards when trying to determine "safe" stack pointers
- // sp must be within the usable part of the stack (not in guards)
- if (!thread->is_in_usable_stack(_SP)) {
- return false;
- }
-
- // unextended sp must be within the stack and above or equal sp
- if (!thread->is_in_stack_range_incl(_UNEXTENDED_SP, _SP)) {
- return false;
- }
-
- // an fp must be within the stack and above (but not equal) sp
- bool fp_safe = thread->is_in_stack_range_excl(_FP, _SP);
-
- // We know sp/unextended_sp are safe only fp is questionable here
-
- // If the current frame is known to the code cache then we can attempt to
- // to construct the sender and do some validation of it. This goes a long way
- // toward eliminating issues when we get in frame construction code
-
- if (_cb != NULL ) {
-
- // First check if frame is complete and tester is reliable
- // Unfortunately we can only check frame complete for runtime stubs and nmethod
- // other generic buffer blobs are more problematic so we just assume they are
- // ok. adapter blobs never have a frame complete and are never ok.
-
- if (!_cb->is_frame_complete_at(_pc)) {
- if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
- return false;
- }
- }
-
- // Could just be some random pointer within the codeBlob
- if (!_cb->code_contains(_pc)) {
- return false;
- }
-
- // Entry frame checks
- if (is_entry_frame()) {
- // an entry frame must have a valid fp.
- return fp_safe && is_entry_frame_valid(thread);
- }
-
- intptr_t* younger_sp = sp();
- intptr_t* _SENDER_SP = sender_sp(); // sender is actually just _FP
- bool adjusted_stack = is_interpreted_frame();
-
- address sender_pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset;
-
-
- // We must always be able to find a recognizable pc
- CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
- if (sender_pc == NULL || sender_blob == NULL) {
- return false;
- }
-
- // Could be a zombie method
- if (sender_blob->is_zombie() || sender_blob->is_unloaded()) {
- return false;
- }
-
- // It should be safe to construct the sender though it might not be valid
-
- frame sender(_SENDER_SP, younger_sp, adjusted_stack);
-
- // Do we have a valid fp?
- address sender_fp = (address) sender.fp();
-
- // an fp must be within the stack and above (but not equal) current frame's _FP
-
- if (!thread->is_in_stack_range_excl(sender_fp, _FP)) {
- return false;
- }
-
-
- // If the potential sender is the interpreter then we can do some more checking
- if (Interpreter::contains(sender_pc)) {
- return sender.is_interpreted_frame_valid(thread);
- }
-
- // Could just be some random pointer within the codeBlob
- if (!sender.cb()->code_contains(sender_pc)) {
- return false;
- }
-
- // We should never be able to see an adapter if the current frame is something from code cache
- if (sender_blob->is_adapter_blob()) {
- return false;
- }
-
- if (sender.is_entry_frame()) {
- // Validate the JavaCallWrapper an entry frame must have
- address jcw = (address)sender.entry_frame_call_wrapper();
-
- return thread->is_in_stack_range_excl(jcw, sender_fp);
- }
-
- // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size
- // because you must allocate window space
-
- if (sender_blob->frame_size() <= 0) {
- assert(!sender_blob->is_compiled(), "should count return address at least");
- return false;
- }
-
- // The sender should positively be an nmethod or call_stub. On sparc we might in fact see something else.
- // The cause of this is because at a save instruction the O7 we get is a leftover from an earlier
- // window use. So if a runtime stub creates two frames (common in fastdebug/debug) then we see the
- // stale pc. So if the sender blob is not something we'd expect we have little choice but to declare
- // the stack unwalkable. pd_get_top_frame_for_signal_handler tries to recover from this by unwinding
- // that initial frame and retrying.
-
- if (!sender_blob->is_compiled()) {
- return false;
- }
-
- // Could put some more validation for the potential non-interpreted sender
- // frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
-
- // One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb
-
- // We've validated the potential sender that would be created
-
- return true;
-
- }
-
- // Must be native-compiled frame. Since sender will try and use fp to find
- // linkages it must be safe
-
- if (!fp_safe) return false;
-
- // could try and do some more potential verification of native frame if we could think of some...
-
- return true;
-}
-
-// constructors
-
-// Construct an unpatchable, deficient frame
-void frame::init(intptr_t* sp, address pc, CodeBlob* cb) {
- assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp");
- _sp = sp;
- _younger_sp = NULL;
- _pc = pc;
- _cb = cb;
- _sp_adjustment_by_callee = 0;
- assert(pc == NULL && cb == NULL || pc != NULL, "can't have a cb and no pc!");
- if (_cb == NULL && _pc != NULL ) {
- _cb = CodeCache::find_blob(_pc);
- }
- _deopt_state = unknown;
-}
-
-frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
- init(sp, pc, cb);
-}
-
-frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) :
- _sp(sp),
- _younger_sp(younger_sp),
- _deopt_state(unknown),
- _sp_adjustment_by_callee(0) {
- if (younger_sp == NULL) {
- // make a deficient frame which doesn't know where its PC is
- _pc = NULL;
- _cb = NULL;
- } else {
- _pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset;
- assert( (intptr_t*)younger_sp[FP->sp_offset_in_saved_window()] == (intptr_t*)((intptr_t)sp - STACK_BIAS), "younger_sp must be valid");
- // Any frame we ever build should always "safe" therefore we should not have to call
- // find_blob_unsafe
- // In case of native stubs, the pc retrieved here might be
- // wrong. (the _last_native_pc will have the right value)
- // So do not put add any asserts on the _pc here.
- }
-
- if (_pc != NULL)
- _cb = CodeCache::find_blob(_pc);
-
- // Check for MethodHandle call sites.
- if (_cb != NULL) {
- CompiledMethod* nm = _cb->as_compiled_method_or_null();
- if (nm != NULL) {
- if (nm->is_deopt_mh_entry(_pc) || nm->is_method_handle_return(_pc)) {
- _sp_adjustment_by_callee = (intptr_t*) ((intptr_t) sp[L7_mh_SP_save->sp_offset_in_saved_window()] + STACK_BIAS) - sp;
- // The SP is already adjusted by this MH call site, don't
- // overwrite this value with the wrong interpreter value.
- younger_frame_is_interpreted = false;
- }
- }
- }
-
- if (younger_frame_is_interpreted) {
- // compute adjustment to this frame's SP made by its interpreted callee
- _sp_adjustment_by_callee = (intptr_t*) ((intptr_t) younger_sp[I5_savedSP->sp_offset_in_saved_window()] + STACK_BIAS) - sp;
- }
-
- // It is important that the frame is fully constructed when we do
- // this lookup as get_deopt_original_pc() needs a correct value for
- // unextended_sp() which uses _sp_adjustment_by_callee.
- if (_pc != NULL) {
- address original_pc = CompiledMethod::get_deopt_original_pc(this);
- if (original_pc != NULL) {
- _pc = original_pc;
- _deopt_state = is_deoptimized;
- } else {
- _deopt_state = not_deoptimized;
- }
- }
-}
-
-#ifndef PRODUCT
-// This is a generic constructor which is only used by pns() in debug.cpp.
-frame::frame(void* sp, void* fp, void* pc) {
- init((intptr_t*)sp, (address)pc, NULL);
-}
-
-extern "C" void findpc(intptr_t x);
-
-void frame::pd_ps() {
- intptr_t* curr_sp = sp();
- intptr_t* prev_sp = curr_sp - 1;
- intptr_t *pc = NULL;
- intptr_t *next_pc = NULL;
- int count = 0;
- tty->print_cr("register window backtrace from " INTPTR_FORMAT ":", p2i(curr_sp));
- while (curr_sp != NULL && ((intptr_t)curr_sp & 7) == 0 && curr_sp > prev_sp && curr_sp < prev_sp+1000) {
- pc = next_pc;
- next_pc = (intptr_t*) curr_sp[I7->sp_offset_in_saved_window()];
- tty->print("[%d] curr_sp=" INTPTR_FORMAT " pc=", count, p2i(curr_sp));
- findpc((intptr_t)pc);
- if (WizardMode && Verbose) {
- // print register window contents also
- tty->print_cr(" L0..L7: {"
- INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " "
- INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " ",
- curr_sp[0+0], curr_sp[0+1], curr_sp[0+2], curr_sp[0+3],
- curr_sp[0+4], curr_sp[0+5], curr_sp[0+6], curr_sp[0+7]);
- tty->print_cr(" I0..I7: {"
- INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " "
- INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " ",
- curr_sp[8+0], curr_sp[8+1], curr_sp[8+2], curr_sp[8+3],
- curr_sp[8+4], curr_sp[8+5], curr_sp[8+6], curr_sp[8+7]);
- // (and print stack frame contents too??)
-
- CodeBlob *b = CodeCache::find_blob((address) pc);
- if (b != NULL) {
- if (b->is_nmethod()) {
- Method* m = ((nmethod*)b)->method();
- int nlocals = m->max_locals();
- int nparams = m->size_of_parameters();
- tty->print_cr("compiled java method (locals = %d, params = %d)", nlocals, nparams);
- }
- }
- }
- prev_sp = curr_sp;
- curr_sp = (intptr_t *)curr_sp[FP->sp_offset_in_saved_window()];
- curr_sp = (intptr_t *)((intptr_t)curr_sp + STACK_BIAS);
- count += 1;
- }
- if (curr_sp != NULL)
- tty->print("[%d] curr_sp=" INTPTR_FORMAT " [bogus sp!]", count, p2i(curr_sp));
-}
-
-#endif // PRODUCT
-
-bool frame::is_interpreted_frame() const {
- return Interpreter::contains(pc());
-}
-
-// sender_sp
-
-intptr_t* frame::interpreter_frame_sender_sp() const {
- assert(is_interpreted_frame(), "interpreted frame expected");
- return fp();
-}
-
-void frame::set_interpreter_frame_sender_sp(intptr_t* sender_sp) {
- assert(is_interpreted_frame(), "interpreted frame expected");
- Unimplemented();
-}
-
-frame frame::sender_for_entry_frame(RegisterMap *map) const {
- assert(map != NULL, "map must be set");
- // Java frame called from C; skip all C frames and return top C
- // frame of that chunk as the sender
- JavaFrameAnchor* jfa = entry_frame_call_wrapper()->anchor();
- assert(!entry_frame_is_first(), "next Java fp must be non zero");
- assert(jfa->last_Java_sp() > _sp, "must be above this frame on stack");
- intptr_t* last_Java_sp = jfa->last_Java_sp();
- // Since we are walking the stack now this nested anchor is obviously walkable
- // even if it wasn't when it was stacked.
- if (!jfa->walkable()) {
- // Capture _last_Java_pc (if needed) and mark anchor walkable.
- jfa->capture_last_Java_pc(_sp);
- }
- assert(jfa->last_Java_pc() != NULL, "No captured pc!");
- map->clear();
- map->make_integer_regs_unsaved();
- map->shift_window(last_Java_sp, NULL);
- assert(map->include_argument_oops(), "should be set by clear");
- return frame(last_Java_sp, frame::unpatchable, jfa->last_Java_pc());
-}
-
-frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
- ShouldNotCallThis();
- return sender(map);
-}
-
-frame frame::sender_for_compiled_frame(RegisterMap *map) const {
- ShouldNotCallThis();
- return sender(map);
-}
-
-frame frame::sender(RegisterMap* map) const {
- assert(map != NULL, "map must be set");
-
- assert(CodeCache::find_blob_unsafe(_pc) == _cb, "inconsistent");
-
- // Default is not to follow arguments; update it accordingly below
- map->set_include_argument_oops(false);
-
- if (is_entry_frame()) return sender_for_entry_frame(map);
-
- intptr_t* younger_sp = sp();
- intptr_t* sp = sender_sp();
-
- // Note: The version of this operation on any platform with callee-save
- // registers must update the register map (if not null).
- // In order to do this correctly, the various subtypes of
- // of frame (interpreted, compiled, glue, native),
- // must be distinguished. There is no need on SPARC for
- // such distinctions, because all callee-save registers are
- // preserved for all frames via SPARC-specific mechanisms.
- //
- // *** HOWEVER, *** if and when we make any floating-point
- // registers callee-saved, then we will have to copy over
- // the RegisterMap update logic from the Intel code.
-
- // The constructor of the sender must know whether this frame is interpreted so it can set the
- // sender's _sp_adjustment_by_callee field. An osr adapter frame was originally
- // interpreted but its pc is in the code cache (for c1 -> osr_frame_return_id stub), so it must be
- // explicitly recognized.
-
-
- bool frame_is_interpreted = is_interpreted_frame();
- if (frame_is_interpreted) {
- map->make_integer_regs_unsaved();
- map->shift_window(sp, younger_sp);
- } else if (_cb != NULL) {
- // Update the locations of implicitly saved registers to be their
- // addresses in the register save area.
- // For %o registers, the addresses of %i registers in the next younger
- // frame are used.
- map->shift_window(sp, younger_sp);
- if (map->update_map()) {
- // Tell GC to use argument oopmaps for some runtime stubs that need it.
- // For C1, the runtime stub might not have oop maps, so set this flag
- // outside of update_register_map.
- map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
- if (_cb->oop_maps() != NULL) {
- OopMapSet::update_register_map(this, map);
- }
- }
- }
- return frame(sp, younger_sp, frame_is_interpreted);
-}
-
-
-void frame::patch_pc(Thread* thread, address pc) {
- assert(_cb == CodeCache::find_blob(pc), "unexpected pc");
- vmassert(_deopt_state != unknown, "frame is unpatchable");
- if (thread == Thread::current()) {
- StubRoutines::Sparc::flush_callers_register_windows_func()();
- }
- if (TracePcPatching) {
- // QQQ this assert is invalid (or too strong anyway) sice _pc could
- // be original pc and frame could have the deopt pc.
- // assert(_pc == *O7_addr() + pc_return_offset, "frame has wrong pc");
- tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
- p2i(O7_addr()), p2i(_pc), p2i(pc));
- }
- *O7_addr() = pc - pc_return_offset;
- address original_pc = CompiledMethod::get_deopt_original_pc(this);
- if (original_pc != NULL) {
- assert(original_pc == _pc, "expected original to be stored before patching");
- _deopt_state = is_deoptimized;
- } else {
- _deopt_state = not_deoptimized;
- }
-}
-
-
-static bool sp_is_valid(intptr_t* old_sp, intptr_t* young_sp, intptr_t* sp) {
- return (((intptr_t)sp & (2*wordSize-1)) == 0 &&
- sp <= old_sp &&
- sp >= young_sp);
-}
-
-
-/*
- Find the (biased) sp that is just younger than old_sp starting at sp.
- If not found return NULL. Register windows are assumed to be flushed.
-*/
-intptr_t* frame::next_younger_sp_or_null(intptr_t* old_sp, intptr_t* sp) {
-
- intptr_t* previous_sp = NULL;
- intptr_t* orig_sp = sp;
-
- int max_frames = (old_sp - sp) / 16; // Minimum frame size is 16
- int max_frame2 = max_frames;
- while(sp != old_sp && sp_is_valid(old_sp, orig_sp, sp)) {
- if (max_frames-- <= 0)
- // too many frames have gone by; invalid parameters given to this function
- break;
- previous_sp = sp;
- sp = (intptr_t*)sp[FP->sp_offset_in_saved_window()];
- sp = (intptr_t*)((intptr_t)sp + STACK_BIAS);
- }
-
- return (sp == old_sp ? previous_sp : NULL);
-}
-
-/*
- Determine if "sp" is a valid stack pointer. "sp" is assumed to be younger than
- "valid_sp". So if "sp" is valid itself then it should be possible to walk frames
- from "sp" to "valid_sp". The assumption is that the registers windows for the
- thread stack in question are flushed.
-*/
-bool frame::is_valid_stack_pointer(intptr_t* valid_sp, intptr_t* sp) {
- return next_younger_sp_or_null(valid_sp, sp) != NULL;
-}
-
-bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
- assert(is_interpreted_frame(), "Not an interpreted frame");
- // These are reasonable sanity checks
- if (fp() == 0 || (intptr_t(fp()) & (2*wordSize-1)) != 0) {
- return false;
- }
- if (sp() == 0 || (intptr_t(sp()) & (2*wordSize-1)) != 0) {
- return false;
- }
-
- const intptr_t interpreter_frame_initial_sp_offset = interpreter_frame_vm_local_words;
- if (fp() + interpreter_frame_initial_sp_offset < sp()) {
- return false;
- }
- // These are hacks to keep us out of trouble.
- // The problem with these is that they mask other problems
- if (fp() <= sp()) { // this attempts to deal with unsigned comparison above
- return false;
- }
- // do some validation of frame elements
-
- // first the method
-
- Method* m = *interpreter_frame_method_addr();
-
- // validate the method we'd find in this potential sender
- if (!Method::is_valid_method(m)) return false;
-
- // stack frames shouldn't be much larger than max_stack elements
-
- if (fp() - unextended_sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) {
- return false;
- }
-
- // validate bci/bcp
-
- address bcp = interpreter_frame_bcp();
- if (m->validate_bci_from_bcp(bcp) < 0) {
- return false;
- }
-
- // validate ConstantPoolCache*
- ConstantPoolCache* cp = *interpreter_frame_cache_addr();
- if (MetaspaceObj::is_valid(cp) == false) return false;
-
- // validate locals
-
- address locals = (address) *interpreter_frame_locals_addr();
- return thread->is_in_stack_range_incl(locals, (address)fp());
-}
-
-
-// Windows have been flushed on entry (but not marked). Capture the pc that
-// is the return address to the frame that contains "sp" as its stack pointer.
-// This pc resides in the called of the frame corresponding to "sp".
-// As a side effect we mark this JavaFrameAnchor as having flushed the windows.
-// This side effect lets us mark stacked JavaFrameAnchors (stacked in the
-// call_helper) as flushed when we have flushed the windows for the most
-// recent (i.e. current) JavaFrameAnchor. This saves useless flushing calls
-// and lets us find the pc just once rather than multiple times as it did
-// in the bad old _post_Java_state days.
-//
-void JavaFrameAnchor::capture_last_Java_pc(intptr_t* sp) {
- if (last_Java_sp() != NULL && last_Java_pc() == NULL) {
- // try and find the sp just younger than _last_Java_sp
- intptr_t* _post_Java_sp = frame::next_younger_sp_or_null(last_Java_sp(), sp);
- // Really this should never fail otherwise VM call must have non-standard
- // frame linkage (bad) or stack is not properly flushed (worse).
- guarantee(_post_Java_sp != NULL, "bad stack!");
- _last_Java_pc = (address) _post_Java_sp[ I7->sp_offset_in_saved_window()] + frame::pc_return_offset;
-
- }
- set_window_flushed();
-}
-
-void JavaFrameAnchor::make_walkable(JavaThread* thread) {
- if (walkable()) return;
- // Eventually make an assert
- guarantee(Thread::current() == (Thread*)thread, "only current thread can flush its registers");
- // We always flush in case the profiler wants it but we won't mark
- // the windows as flushed unless we have a last_Java_frame
- intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()();
- if (last_Java_sp() != NULL ) {
- capture_last_Java_pc(sp);
- }
-}
-
-intptr_t* frame::entry_frame_argument_at(int offset) const {
- // convert offset to index to deal with tsi
- int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
-
- intptr_t* LSP = (intptr_t*) sp()[Lentry_args->sp_offset_in_saved_window()];
- return &LSP[index+1];
-}
-
-
-BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) {
- assert(is_interpreted_frame(), "interpreted frame expected");
- Method* method = interpreter_frame_method();
- BasicType type = method->result_type();
-
- if (method->is_native()) {
- // Prior to notifying the runtime of the method_exit the possible result
- // value is saved to l_scratch and d_scratch.
-
- intptr_t* l_scratch = fp() + interpreter_frame_l_scratch_fp_offset;
- intptr_t* d_scratch = fp() + interpreter_frame_d_scratch_fp_offset;
-
- address l_addr = (address)l_scratch;
- // On 64-bit the result for 1/8/16/32-bit result types is in the other
- // word half
- l_addr += wordSize/2;
-
- switch (type) {
- case T_OBJECT:
- case T_ARRAY: {
- oop obj = cast_to_oop(at(interpreter_frame_oop_temp_offset));
- assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check");
- *oop_result = obj;
- break;
- }
-
- case T_BOOLEAN : { jint* p = (jint*)l_addr; value_result->z = (jboolean)((*p) & 0x1); break; }
- case T_BYTE : { jint* p = (jint*)l_addr; value_result->b = (jbyte)((*p) & 0xff); break; }
- case T_CHAR : { jint* p = (jint*)l_addr; value_result->c = (jchar)((*p) & 0xffff); break; }
- case T_SHORT : { jint* p = (jint*)l_addr; value_result->s = (jshort)((*p) & 0xffff); break; }
- case T_INT : value_result->i = *(jint*)l_addr; break;
- case T_LONG : value_result->j = *(jlong*)l_scratch; break;
- case T_FLOAT : value_result->f = *(jfloat*)d_scratch; break;
- case T_DOUBLE : value_result->d = *(jdouble*)d_scratch; break;
- case T_VOID : /* Nothing to do */ break;
- default : ShouldNotReachHere();
- }
- } else {
- intptr_t* tos_addr = interpreter_frame_tos_address();
-
- switch(type) {
- case T_OBJECT:
- case T_ARRAY: {
- oop obj = cast_to_oop(*tos_addr);
- assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check");
- *oop_result = obj;
- break;
- }
- case T_BOOLEAN : { jint* p = (jint*)tos_addr; value_result->z = (jboolean)((*p) & 0x1); break; }
- case T_BYTE : { jint* p = (jint*)tos_addr; value_result->b = (jbyte)((*p) & 0xff); break; }
- case T_CHAR : { jint* p = (jint*)tos_addr; value_result->c = (jchar)((*p) & 0xffff); break; }
- case T_SHORT : { jint* p = (jint*)tos_addr; value_result->s = (jshort)((*p) & 0xffff); break; }
- case T_INT : value_result->i = *(jint*)tos_addr; break;
- case T_LONG : value_result->j = *(jlong*)tos_addr; break;
- case T_FLOAT : value_result->f = *(jfloat*)tos_addr; break;
- case T_DOUBLE : value_result->d = *(jdouble*)tos_addr; break;
- case T_VOID : /* Nothing to do */ break;
- default : ShouldNotReachHere();
- }
- };
-
- return type;
-}
-
-// Lesp pointer is one word lower than the top item on the stack.
-intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
- int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize) - 1;
- return &interpreter_frame_tos_address()[index];
-}
-
-
-#ifndef PRODUCT
-
-#define DESCRIBE_FP_OFFSET(name) \
- values.describe(frame_no, fp() + frame::name##_offset, #name)
-
-void frame::describe_pd(FrameValues& values, int frame_no) {
- for (int w = 0; w < frame::register_save_words; w++) {
- values.describe(frame_no, sp() + w, err_msg("register save area word %d", w), 1);
- }
-
- if (is_interpreted_frame()) {
- DESCRIBE_FP_OFFSET(interpreter_frame_d_scratch_fp);
- DESCRIBE_FP_OFFSET(interpreter_frame_l_scratch_fp);
- DESCRIBE_FP_OFFSET(interpreter_frame_mirror);
- DESCRIBE_FP_OFFSET(interpreter_frame_oop_temp);
-
- // esp, according to Lesp (e.g. not depending on bci), if seems valid
- intptr_t* esp = *interpreter_frame_esp_addr();
- if ((esp >= sp()) && (esp < fp())) {
- values.describe(-1, esp, "*Lesp");
- }
- }
-
- if (!is_compiled_frame()) {
- if (frame::callee_aggregate_return_pointer_words != 0) {
- values.describe(frame_no, sp() + frame::callee_aggregate_return_pointer_sp_offset, "callee_aggregate_return_pointer_word");
- }
- for (int w = 0; w < frame::callee_register_argument_save_area_words; w++) {
- values.describe(frame_no, sp() + frame::callee_register_argument_save_area_sp_offset + w,
- err_msg("callee_register_argument_save_area_words %d", w));
- }
- }
-}
-
-#endif
-
-intptr_t *frame::initial_deoptimization_info() {
- // unused... but returns fp() to minimize changes introduced by 7087445
- return fp();
-}
diff --git a/src/hotspot/cpu/sparc/frame_sparc.hpp b/src/hotspot/cpu/sparc/frame_sparc.hpp
deleted file mode 100644
index 9fcae7a34e6..00000000000
--- a/src/hotspot/cpu/sparc/frame_sparc.hpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_FRAME_SPARC_HPP
-#define CPU_SPARC_FRAME_SPARC_HPP
-
-#include "runtime/synchronizer.hpp"
-
-// A frame represents a physical stack frame (an activation). Frames can be
-// C or Java frames, and the Java frames can be interpreted or compiled.
-// In contrast, vframes represent source-level activations, so that one physical frame
-// can correspond to multiple source level frames because of inlining.
-// A frame is comprised of {pc, sp, younger_sp}
-
-
-// Layout of asm interpreter frame:
-//
-// 0xfffffff
-// ......
-// [last extra incoming arg, (local # Nargs > 6 ? Nargs-1 : undef)]
-// .. Note: incoming args are copied to local frame area upon entry
-// [first extra incoming arg, (local # Nargs > 6 ? 6 : undef)]
-// [6 words for C-arg storage (unused)] Are this and next one really needed?
-// [C-aggregate-word (unused)] Yes, if want extra params to be in same place as C convention
-// [16 words for register saving] <--- FP
-// [interpreter_frame_vm_locals ] (see below)
-
-// Note: Llocals is always double-word aligned
-// [first local i.e. local # 0] <-- Llocals
-// ...
-// [last local, i.e. local # Nlocals-1]
-
-// [monitors ]
-// ....
-// [monitors ] <-- Lmonitors (same as Llocals + 6*4 if none)
-// (must be double-word aligned because
-// monitor element size is constrained to
-// doubleword)
-//
-// <-- Lesp (points 1 past TOS)
-// [bottom word used for stack ]
-// ...
-// [top word used for stack] (first word of stack is double-word aligned)
-
-// [space for outgoing args (conservatively allocated as max_stack - 6 + interpreter_frame_extra_outgoing_argument_words)]
-// [6 words for C-arg storage]
-// [C-aggregate-word (unused)]
-// [16 words for register saving] <--- SP
-// ...
-// 0x0000000
-//
-// The in registers and local registers are preserved in a block at SP.
-//
-// The first six in registers (I0..I5) hold the first six locals.
-// The locals are used as follows:
-// Lesp first free element of expression stack
-// (which grows towards __higher__ addresses)
-// Lbcp is set to address of bytecode to execute
-// It may at times (during GC) be an index instead.
-// Lmethod the method being interpreted
-// Llocals the base pointer for accessing the locals array
-// (lower-numbered locals have lower addresses)
-// Lmonitors the base pointer for accessing active monitors
-// Lcache a saved pointer to the method's constant pool cache
-//
-//
-// When calling out to another method,
-// G5_method is set to method to call, G5_inline_cache_klass may be set,
-// parameters are put in O registers, and also extra parameters
-// must be cleverly copied from the top of stack to the outgoing param area in the frame,
-
-// All frames:
-
- public:
-
- enum {
- // normal return address is 2 words past PC
- pc_return_offset = 2 * BytesPerInstWord,
-
- // size of each block, in order of increasing address:
- register_save_words = 16,
- callee_aggregate_return_pointer_words = 0,
- callee_register_argument_save_area_words = 6,
- // memory_parameter_words = ,
-
- // offset of each block, in order of increasing address:
- // (note: callee_register_argument_save_area_words == Assembler::n_register_parameters)
- register_save_words_sp_offset = 0,
- callee_aggregate_return_pointer_sp_offset = register_save_words_sp_offset + register_save_words,
- callee_register_argument_save_area_sp_offset = callee_aggregate_return_pointer_sp_offset + callee_aggregate_return_pointer_words,
- memory_parameter_word_sp_offset = callee_register_argument_save_area_sp_offset + callee_register_argument_save_area_words,
- varargs_offset = memory_parameter_word_sp_offset
- };
-
- private:
- intptr_t* _younger_sp; // optional SP of callee (used to locate O7)
- int _sp_adjustment_by_callee; // adjustment in words to SP by callee for making locals contiguous
-
- // Note: On SPARC, unlike Intel, the saved PC for a stack frame
- // is stored at a __variable__ distance from that frame's SP.
- // (In fact, it may be in the register save area of the callee frame,
- // but that fact need not bother us.) Thus, we must store the
- // address of that saved PC explicitly. On the other hand, SPARC
- // stores the FP for a frame at a fixed offset from the frame's SP,
- // so there is no need for a separate "frame::_fp" field.
-
- public:
- // Accessors
-
- intptr_t* younger_sp() const {
- assert(_younger_sp != NULL, "frame must possess a younger_sp");
- return _younger_sp;
- }
-
- int callee_sp_adjustment() const { return _sp_adjustment_by_callee; }
- void set_sp_adjustment_by_callee(int number_of_words) { _sp_adjustment_by_callee = number_of_words; }
-
- // Constructors
-
- // This constructor relies on the fact that the creator of a frame
- // has flushed register windows which the frame will refer to, and
- // that those register windows will not be reloaded until the frame is
- // done reading and writing the stack. Moreover, if the "younger_sp"
- // argument points into the register save area of the next younger
- // frame (though it need not), the register window for that next
- // younger frame must also stay flushed. (The caller is responsible
- // for ensuring this.)
-
- frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_adjusted_stack = false);
-
- // make a deficient frame which doesn't know where its PC is:
- enum unpatchable_t { unpatchable };
- frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL);
-
- void init(intptr_t* sp, address pc, CodeBlob* cb);
-
- // Walk from sp outward looking for old_sp, and return old_sp's predecessor
- // (i.e. return the sp from the frame where old_sp is the fp).
- // Register windows are assumed to be flushed for the stack in question.
-
- static intptr_t* next_younger_sp_or_null(intptr_t* old_sp, intptr_t* sp);
-
- // Return true if sp is a younger sp in the stack described by valid_sp.
- static bool is_valid_stack_pointer(intptr_t* valid_sp, intptr_t* sp);
-
- public:
- // accessors for the instance variables
- intptr_t* fp() const { return (intptr_t*) ((intptr_t)(sp()[FP->sp_offset_in_saved_window()]) + STACK_BIAS ); }
-
- // All frames
-
- intptr_t* fp_addr_at(int index) const { return &fp()[index]; }
- intptr_t* sp_addr_at(int index) const { return &sp()[index]; }
- intptr_t fp_at( int index) const { return *fp_addr_at(index); }
- intptr_t sp_at( int index) const { return *sp_addr_at(index); }
-
- private:
- inline address* I7_addr() const;
- inline address* O7_addr() const;
-
- inline address* I0_addr() const;
- inline address* O0_addr() const;
- intptr_t* younger_sp_addr_at(int index) const { return &younger_sp()[index]; }
-
- public:
- // access to SPARC arguments and argument registers
-
- // Assumes reg is an in/local register
- intptr_t* register_addr(Register reg) const {
- return sp_addr_at(reg->sp_offset_in_saved_window());
- }
-
- // Assumes reg is an out register
- intptr_t* out_register_addr(Register reg) const {
- return younger_sp_addr_at(reg->after_save()->sp_offset_in_saved_window());
- }
-
-
- // Interpreter frames
-
- public:
- // Asm interpreter
- enum interpreter_frame_vm_locals {
- // 2 words, also used to save float regs across calls to C
- interpreter_frame_d_scratch_fp_offset = -2,
- interpreter_frame_l_scratch_fp_offset = -4,
- interpreter_frame_mirror_offset = -5, // keep interpreted method alive
-
- interpreter_frame_oop_temp_offset = -6, // for native calls only
- interpreter_frame_vm_locals_fp_offset = -6, // should be same as above, and should be zero mod 8
-
- interpreter_frame_vm_local_words = -interpreter_frame_vm_locals_fp_offset,
-
-
- // interpreter frame set-up needs to save 2 extra words in outgoing param area
- // for class and jnienv arguments for native stubs (see nativeStubGen_sparc.cpp_
-
- interpreter_frame_extra_outgoing_argument_words = 2
- };
-
- enum compiler_frame_fixed_locals {
- compiler_frame_vm_locals_fp_offset = -2
- };
-
- private:
- ConstantPoolCache** interpreter_frame_cpoolcache_addr() const;
-
- // where Lmonitors is saved:
- inline BasicObjectLock** interpreter_frame_monitors_addr() const;
- inline intptr_t** interpreter_frame_esp_addr() const;
-
- inline void interpreter_frame_set_tos_address(intptr_t* x);
-
- // monitors:
-
- // next two fns read and write Lmonitors value,
- private:
- BasicObjectLock* interpreter_frame_monitors() const;
- void interpreter_frame_set_monitors(BasicObjectLock* monitors);
- public:
-
- static jint interpreter_frame_expression_stack_direction() { return -1; }
-
-#endif // CPU_SPARC_FRAME_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/frame_sparc.inline.hpp b/src/hotspot/cpu/sparc/frame_sparc.inline.hpp
deleted file mode 100644
index 7f700cc7596..00000000000
--- a/src/hotspot/cpu/sparc/frame_sparc.inline.hpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_FRAME_SPARC_INLINE_HPP
-#define CPU_SPARC_FRAME_SPARC_INLINE_HPP
-
-#include "asm/macroAssembler.hpp"
-#include "code/vmreg.inline.hpp"
-#include "utilities/align.hpp"
-
-// Inline functions for SPARC frames:
-
-// Constructors
-
-inline frame::frame() {
- _pc = NULL;
- _sp = NULL;
- _younger_sp = NULL;
- _cb = NULL;
- _deopt_state = unknown;
- _sp_adjustment_by_callee = 0;
-}
-
-// Accessors:
-
-inline bool frame::equal(frame other) const {
- bool ret = sp() == other.sp()
- && fp() == other.fp()
- && pc() == other.pc();
- assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction");
- return ret;
-}
-
-// Return unique id for this frame. The id must have a value where we can distinguish
-// identity and younger/older relationship. NULL represents an invalid (incomparable)
-// frame.
-inline intptr_t* frame::id(void) const { return unextended_sp(); }
-
-// Return true if the frame is older (less recent activation) than the frame represented by id
-inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id");
- return this->id() > id ; }
-
-inline int frame::frame_size(RegisterMap* map) const { return sender_sp() - sp(); }
-
-inline intptr_t* frame::link() const { return (intptr_t *)(fp()[FP->sp_offset_in_saved_window()] + STACK_BIAS); }
-
-inline intptr_t* frame::unextended_sp() const { return sp() + _sp_adjustment_by_callee; }
-
-// return address:
-
-inline address frame::sender_pc() const { return *I7_addr() + pc_return_offset; }
-
-inline address* frame::I7_addr() const { return (address*) &sp()[ I7->sp_offset_in_saved_window()]; }
-inline address* frame::I0_addr() const { return (address*) &sp()[ I0->sp_offset_in_saved_window()]; }
-
-inline address* frame::O7_addr() const { return (address*) &younger_sp()[ I7->sp_offset_in_saved_window()]; }
-inline address* frame::O0_addr() const { return (address*) &younger_sp()[ I0->sp_offset_in_saved_window()]; }
-
-inline intptr_t* frame::sender_sp() const { return fp(); }
-
-inline intptr_t* frame::real_fp() const { return fp(); }
-
-inline intptr_t** frame::interpreter_frame_locals_addr() const {
- return (intptr_t**) sp_addr_at( Llocals->sp_offset_in_saved_window());
-}
-
-inline intptr_t* frame::interpreter_frame_bcp_addr() const {
- return (intptr_t*) sp_addr_at( Lbcp->sp_offset_in_saved_window());
-}
-
-inline intptr_t* frame::interpreter_frame_mdp_addr() const {
- // %%%%% reinterpreting ImethodDataPtr as a mdx
- return (intptr_t*) sp_addr_at( ImethodDataPtr->sp_offset_in_saved_window());
-}
-
-// bottom(base) of the expression stack (highest address)
-inline intptr_t* frame::interpreter_frame_expression_stack() const {
- return (intptr_t*)interpreter_frame_monitors() - 1;
-}
-
-// top of expression stack (lowest address)
-inline intptr_t* frame::interpreter_frame_tos_address() const {
- return *interpreter_frame_esp_addr() + 1;
-}
-
-inline BasicObjectLock** frame::interpreter_frame_monitors_addr() const {
- return (BasicObjectLock**) sp_addr_at(Lmonitors->sp_offset_in_saved_window());
-}
-inline intptr_t** frame::interpreter_frame_esp_addr() const {
- return (intptr_t**)sp_addr_at(Lesp->sp_offset_in_saved_window());
-}
-
-inline void frame::interpreter_frame_set_tos_address( intptr_t* x ) {
- *interpreter_frame_esp_addr() = x - 1;
-}
-
-// monitor elements
-
-// in keeping with Intel side: end is lower in memory than begin;
-// and beginning element is oldest element
-// Also begin is one past last monitor.
-
-inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
- int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words, WordsPerLong);
- return (BasicObjectLock *)fp_addr_at(-rounded_vm_local_words);
-}
-
-inline BasicObjectLock* frame::interpreter_frame_monitor_end() const {
- return interpreter_frame_monitors();
-}
-
-
-inline void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) {
- interpreter_frame_set_monitors(value);
-}
-
-inline int frame::interpreter_frame_monitor_size() {
- return align_up(BasicObjectLock::size(), WordsPerLong);
-}
-
-inline Method** frame::interpreter_frame_method_addr() const {
- return (Method**)sp_addr_at( Lmethod->sp_offset_in_saved_window());
-}
-
-inline BasicObjectLock* frame::interpreter_frame_monitors() const {
- return *interpreter_frame_monitors_addr();
-}
-
-inline void frame::interpreter_frame_set_monitors(BasicObjectLock* monitors) {
- *interpreter_frame_monitors_addr() = monitors;
-}
-
-inline oop* frame::interpreter_frame_mirror_addr() const {
- return (oop*)(fp() + interpreter_frame_mirror_offset);
-}
-
-// Constant pool cache
-
-// where LcpoolCache is saved:
-inline ConstantPoolCache** frame::interpreter_frame_cpoolcache_addr() const {
- return (ConstantPoolCache**)sp_addr_at(LcpoolCache->sp_offset_in_saved_window());
- }
-
-inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const {
- return (ConstantPoolCache**)sp_addr_at( LcpoolCache->sp_offset_in_saved_window());
-}
-
-inline oop* frame::interpreter_frame_temp_oop_addr() const {
- return (oop *)(fp() + interpreter_frame_oop_temp_offset);
-}
-
-
-inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
- // note: adjust this code if the link argument in StubGenerator::call_stub() changes!
- const Argument link = Argument(0, false);
- return (JavaCallWrapper**)&sp()[link.as_in().as_register()->sp_offset_in_saved_window()];
-}
-
-
-inline oop frame::saved_oop_result(RegisterMap* map) const {
- return *((oop*) map->location(O0->as_VMReg()));
-}
-
-inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
- *((oop*) map->location(O0->as_VMReg())) = obj;
-}
-
-#endif // CPU_SPARC_FRAME_SPARC_INLINE_HPP
diff --git a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp
deleted file mode 100644
index f66c58bbba1..00000000000
--- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1BarrierSetAssembler.hpp"
-#include "gc/g1/g1BarrierSetRuntime.hpp"
-#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1DirtyCardQueue.hpp"
-#include "gc/g1/g1SATBMarkQueueSet.hpp"
-#include "gc/g1/g1ThreadLocalData.hpp"
-#include "gc/g1/heapRegion.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "utilities/macros.hpp"
-#ifdef COMPILER1
-#include "c1/c1_LIRAssembler.hpp"
-#include "c1/c1_MacroAssembler.hpp"
-#include "gc/g1/c1/g1BarrierSetC1.hpp"
-#endif
-
-#define __ masm->
-
-void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count) {
- bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
- // With G1, don't generate the call if we statically know that the target in uninitialized
- if (!dest_uninitialized) {
- Register tmp = O5;
- assert_different_registers(addr, count, tmp);
- Label filtered;
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ ld(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ ldsb(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
- }
- // Is marking active?
- __ cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
-
- __ save_frame(0);
- // Save the necessary global regs... will be used after.
- if (addr->is_global()) {
- __ mov(addr, L0);
- }
- if (count->is_global()) {
- __ mov(count, L1);
- }
- __ mov(addr->after_save(), O0);
- // Get the count into O1
- address slowpath = UseCompressedOops ? CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry)
- : CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry);
- __ call(slowpath);
- __ delayed()->mov(count->after_save(), O1);
- if (addr->is_global()) {
- __ mov(L0, addr);
- }
- if (count->is_global()) {
- __ mov(L1, count);
- }
- __ restore();
-
- __ bind(filtered);
- DEBUG_ONLY(__ set(0xDEADC0DE, tmp);) // we have killed tmp
- }
-}
-
-void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count, Register tmp) {
- // Get some new fresh output registers.
- __ save_frame(0);
- __ mov(addr->after_save(), O0);
- __ call(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry));
- __ delayed()->mov(count->after_save(), O1);
- __ restore();
-}
-
-#undef __
-
-static address satb_log_enqueue_with_frame = NULL;
-static u_char* satb_log_enqueue_with_frame_end = NULL;
-
-static address satb_log_enqueue_frameless = NULL;
-static u_char* satb_log_enqueue_frameless_end = NULL;
-
-static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions?
-
-static void generate_satb_log_enqueue(bool with_frame) {
- BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize);
- CodeBuffer buf(bb);
- MacroAssembler masm(&buf);
-
-#define __ masm.
-
- address start = __ pc();
- Register pre_val;
-
- Label refill, restart;
- if (with_frame) {
- __ save_frame(0);
- pre_val = I0; // Was O0 before the save.
- } else {
- pre_val = O0;
- }
-
- int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
- int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
-
- assert(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t) &&
- in_bytes(SATBMarkQueue::byte_width_of_buf()) == sizeof(intptr_t),
- "check sizes in assembly below");
-
- __ bind(restart);
-
- // Load the index into the SATB buffer. SATBMarkQueue::_index is a size_t
- // so ld_ptr is appropriate.
- __ ld_ptr(G2_thread, satb_q_index_byte_offset, L0);
-
- // index == 0?
- __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, satb_q_buf_byte_offset, L1);
- __ sub(L0, oopSize, L0);
-
- __ st_ptr(pre_val, L1, L0); // [_buf + index] := I0
- if (!with_frame) {
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(L0, G2_thread, satb_q_index_byte_offset);
- } else {
- // Not delayed.
- __ st_ptr(L0, G2_thread, satb_q_index_byte_offset);
- }
- if (with_frame) {
- __ ret();
- __ delayed()->restore();
- }
- __ bind(refill);
-
- address handle_zero =
- CAST_FROM_FN_PTR(address,
- &G1SATBMarkQueueSet::handle_zero_index_for_thread);
- // This should be rare enough that we can afford to save all the
- // scratch registers that the calling context might be using.
- __ mov(G1_scratch, L0);
- __ mov(G3_scratch, L1);
- __ mov(G4, L2);
- // We need the value of O0 above (for the write into the buffer), so we
- // save and restore it.
- __ mov(O0, L3);
- // Since the call will overwrite O7, we save and restore that, as well.
- __ mov(O7, L4);
- __ call_VM_leaf(L5, handle_zero, G2_thread);
- __ mov(L0, G1_scratch);
- __ mov(L1, G3_scratch);
- __ mov(L2, G4);
- __ mov(L3, O0);
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ delayed()->mov(L4, O7);
-
- if (with_frame) {
- satb_log_enqueue_with_frame = start;
- satb_log_enqueue_with_frame_end = __ pc();
- } else {
- satb_log_enqueue_frameless = start;
- satb_log_enqueue_frameless_end = __ pc();
- }
-
-#undef __
-}
-
-#define __ masm->
-
-void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
- Register obj,
- Register index,
- int offset,
- Register pre_val,
- Register tmp,
- bool preserve_o_regs) {
- Label filtered;
-
- if (obj == noreg) {
- // We are not loading the previous value so make
- // sure that we don't trash the value in pre_val
- // with the code below.
- assert_different_registers(pre_val, tmp);
- } else {
- // We will be loading the previous value
- // in this code so...
- assert(offset == 0 || index == noreg, "choose one");
- assert(pre_val == noreg, "check this code");
- }
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ ld(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ ldsb(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
- }
-
- // Is marking active?
- __ cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- // Load the previous value...
- if (index == noreg) {
- if (Assembler::is_simm13(offset)) {
- __ load_heap_oop(obj, offset, tmp);
- } else {
- __ set(offset, tmp);
- __ load_heap_oop(obj, tmp, tmp);
- }
- } else {
- __ load_heap_oop(obj, index, tmp);
- }
- // Previous value has been loaded into tmp
- pre_val = tmp;
- }
-
- assert(pre_val != noreg, "must have a real register");
-
- // Is the previous value null?
- __ cmp_and_brx_short(pre_val, G0, Assembler::equal, Assembler::pt, filtered);
-
- // OK, it's not filtered, so we'll need to call enqueue. In the normal
- // case, pre_val will be a scratch G-reg, but there are some cases in
- // which it's an O-reg. In the first case, do a normal call. In the
- // latter, do a save here and call the frameless version.
-
- guarantee(pre_val->is_global() || pre_val->is_out(),
- "Or we need to think harder.");
-
- if (pre_val->is_global() && !preserve_o_regs) {
- __ call(satb_log_enqueue_with_frame);
- __ delayed()->mov(pre_val, O0);
- } else {
- __ save_frame(0);
- __ call(satb_log_enqueue_frameless);
- __ delayed()->mov(pre_val->after_save(), O0);
- __ restore();
- }
-
- __ bind(filtered);
-}
-
-#undef __
-
-static address dirty_card_log_enqueue = 0;
-static u_char* dirty_card_log_enqueue_end = 0;
-
-// This gets to assume that o0 contains the object address.
-static void generate_dirty_card_log_enqueue(CardTable::CardValue* byte_map_base) {
- BufferBlob* bb = BufferBlob::create("dirty_card_enqueue", EnqueueCodeSize*2);
- CodeBuffer buf(bb);
- MacroAssembler masm(&buf);
-#define __ masm.
- address start = __ pc();
-
- Label not_already_dirty, restart, refill, young_card;
-
- __ srlx(O0, CardTable::card_shift, O0);
- AddressLiteral addrlit(byte_map_base);
- __ set(addrlit, O1); // O1 :=
- __ ldub(O0, O1, O2); // O2 := [O0 + O1]
-
- __ cmp_and_br_short(O2, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card);
-
- __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
- __ ldub(O0, O1, O2); // O2 := [O0 + O1]
-
- assert(G1CardTable::dirty_card_val() == 0, "otherwise check this code");
- __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
-
- __ bind(young_card);
- // We didn't take the branch, so we're already dirty: return.
- // Use return-from-leaf
- __ retl();
- __ delayed()->nop();
-
- // Not dirty.
- __ bind(not_already_dirty);
-
- // Get O0 + O1 into a reg by itself
- __ add(O0, O1, O3);
-
- // First, dirty it.
- __ stb(G0, O3, G0); // [cardPtr] := 0 (i.e., dirty).
-
- int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
- int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
- __ bind(restart);
-
- // Load the index into the update buffer. G1DirtyCardQueue::_index is
- // a size_t so ld_ptr is appropriate here.
- __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, L0);
-
- // index == 0?
- __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, L1);
- __ sub(L0, oopSize, L0);
-
- __ st_ptr(O3, L1, L0); // [_buf + index] := I0
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(L0, G2_thread, dirty_card_q_index_byte_offset);
-
- __ bind(refill);
- address handle_zero =
- CAST_FROM_FN_PTR(address,
- &G1DirtyCardQueueSet::handle_zero_index_for_thread);
- // This should be rare enough that we can afford to save all the
- // scratch registers that the calling context might be using.
- __ mov(G1_scratch, L3);
- __ mov(G3_scratch, L5);
- // We need the value of O3 above (for the write into the buffer), so we
- // save and restore it.
- __ mov(O3, L6);
- // Since the call will overwrite O7, we save and restore that, as well.
- __ mov(O7, L4);
-
- __ call_VM_leaf(L7_thread_cache, handle_zero, G2_thread);
- __ mov(L3, G1_scratch);
- __ mov(L5, G3_scratch);
- __ mov(L6, O3);
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ delayed()->mov(L4, O7);
-
- dirty_card_log_enqueue = start;
- dirty_card_log_enqueue_end = __ pc();
- // XXX Should have a guarantee here about not going off the end!
- // Does it already do so? Do an experiment...
-
-#undef __
-
-}
-
-#define __ masm->
-
-void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) {
- Label filtered;
- MacroAssembler* post_filter_masm = masm;
-
- if (new_val == G0) return;
-
- G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set());
-
- __ xor3(store_addr, new_val, tmp);
- __ srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
-
- __ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
-
- // If the "store_addr" register is an "in" or "local" register, move it to
- // a scratch reg so we can pass it as an argument.
- bool use_scr = !(store_addr->is_global() || store_addr->is_out());
- // Pick a scratch register different from "tmp".
- Register scr = (tmp == G1_scratch ? G3_scratch : G1_scratch);
- // Make sure we use up the delay slot!
- if (use_scr) {
- post_filter_masm->mov(store_addr, scr);
- } else {
- post_filter_masm->nop();
- }
- __ save_frame(0);
- __ call(dirty_card_log_enqueue);
- if (use_scr) {
- __ delayed()->mov(scr, O0);
- } else {
- __ delayed()->mov(store_addr->after_save(), O0);
- }
- __ restore();
-
- __ bind(filtered);
-}
-
-void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp) {
- bool in_heap = (decorators & IN_HEAP) != 0;
- bool as_normal = (decorators & AS_NORMAL) != 0;
- assert((decorators & IS_DEST_UNINITIALIZED) == 0, "unsupported");
-
- bool needs_pre_barrier = as_normal;
- // No need for post barrier if storing NULL
- bool needs_post_barrier = val != G0 && in_heap;
-
- bool is_array = (decorators & IS_ARRAY) != 0;
- bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
- bool precise = is_array || on_anonymous;
-
- Register index = dst.has_index() ? dst.index() : noreg;
- int disp = dst.has_disp() ? dst.disp() : 0;
-
- if (needs_pre_barrier) {
- // Load and record the previous value.
- g1_write_barrier_pre(masm, dst.base(), index, disp,
- noreg /* pre_val */,
- tmp, true /*preserve_o_regs*/);
- }
-
- Register new_val = val;
- if (needs_post_barrier) {
- // G1 barrier needs uncompressed oop for region cross check.
- if (UseCompressedOops && val != G0) {
- new_val = tmp;
- __ mov(val, new_val);
- }
- }
-
- BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp);
-
- if (needs_post_barrier) {
- Register base = dst.base();
- if (precise) {
- if (!dst.has_index()) {
- __ add(base, disp, base);
- } else {
- assert(!dst.has_disp(), "not supported yet");
- __ add(base, index, base);
- }
- }
- g1_write_barrier_post(masm, base, new_val, tmp);
- }
-}
-
-void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Address src, Register dst, Register tmp) {
- bool on_oop = is_reference_type(type);
- bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
- bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
- bool on_reference = on_weak || on_phantom;
- // Load the value of the referent field.
- ModRefBarrierSetAssembler::load_at(masm, decorators, type, src, dst, tmp);
- if (on_oop && on_reference) {
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer. Note with
- // these parameters the pre-barrier does not generate
- // the load of the previous value
-
- Register pre_val = dst;
- bool saved = false;
- if (pre_val->is_in()) {
- // The g1_write_barrier_pre method assumes that the pre_val
- // is not in an input register.
- __ save_frame_and_mov(0, pre_val, O0);
- pre_val = O0;
- saved = true;
- }
-
- g1_write_barrier_pre(masm, noreg /* obj */, noreg /* index */, 0 /* offset */,
- pre_val /* pre_val */,
- tmp /* tmp */,
- true /* preserve_o_regs */);
-
- if (saved) {
- __ restore();
- }
- }
-}
-
-void G1BarrierSetAssembler::barrier_stubs_init() {
- if (dirty_card_log_enqueue == 0) {
- G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set());
- CardTable *ct = bs->card_table();
- generate_dirty_card_log_enqueue(ct->byte_map_base());
- assert(dirty_card_log_enqueue != 0, "postcondition.");
- }
- if (satb_log_enqueue_with_frame == 0) {
- generate_satb_log_enqueue(true);
- assert(satb_log_enqueue_with_frame != 0, "postcondition.");
- }
- if (satb_log_enqueue_frameless == 0) {
- generate_satb_log_enqueue(false);
- assert(satb_log_enqueue_frameless != 0, "postcondition.");
- }
-}
-
-#ifdef COMPILER1
-
-#undef __
-#define __ ce->masm()->
-
-void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- // At this point we know that marking is in progress.
- // If do_load() is true then we have to emit the
- // load of the previous value; otherwise it has already
- // been loaded into _pre_val.
-
- __ bind(*stub->entry());
-
- assert(stub->pre_val()->is_register(), "Precondition.");
- Register pre_val_reg = stub->pre_val()->as_register();
-
- if (stub->do_load()) {
- ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
- }
-
- if (__ is_in_wdisp16_range(*stub->continuation())) {
- __ br_null(pre_val_reg, /*annul*/false, Assembler::pt, *stub->continuation());
- } else {
- __ cmp(pre_val_reg, G0);
- __ brx(Assembler::equal, false, Assembler::pn, *stub->continuation());
- }
- __ delayed()->nop();
-
- __ call(bs->pre_barrier_c1_runtime_code_blob()->code_begin());
- __ delayed()->mov(pre_val_reg, G4);
- __ br(Assembler::always, false, Assembler::pt, *stub->continuation());
- __ delayed()->nop();
-}
-
-void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
- G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
- __ bind(*stub->entry());
-
- assert(stub->addr()->is_register(), "Precondition.");
- assert(stub->new_val()->is_register(), "Precondition.");
- Register addr_reg = stub->addr()->as_pointer_register();
- Register new_val_reg = stub->new_val()->as_register();
-
- if (__ is_in_wdisp16_range(*stub->continuation())) {
- __ br_null(new_val_reg, /*annul*/false, Assembler::pt, *stub->continuation());
- } else {
- __ cmp(new_val_reg, G0);
- __ brx(Assembler::equal, false, Assembler::pn, *stub->continuation());
- }
- __ delayed()->nop();
-
- __ call(bs->post_barrier_c1_runtime_code_blob()->code_begin());
- __ delayed()->mov(addr_reg, G4);
- __ br(Assembler::always, false, Assembler::pt, *stub->continuation());
- __ delayed()->nop();
-}
-
-#undef __
-#define __ sasm->
-
-void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
- __ prologue("g1_pre_barrier", false);
-
- // G4: previous value of memory
-
- Register pre_val = G4;
- Register tmp = G1_scratch;
- Register tmp2 = G3_scratch;
-
- Label refill, restart;
- int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
- int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
- int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
-
- // Is marking still active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ ld(G2_thread, satb_q_active_byte_offset, tmp);
- } else {
- assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ ldsb(G2_thread, satb_q_active_byte_offset, tmp);
- }
- __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart);
- __ retl();
- __ delayed()->nop();
-
- __ bind(restart);
- // Load the index into the SATB buffer. SATBMarkQueue::_index is a
- // size_t so ld_ptr is appropriate
- __ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp);
-
- // index == 0?
- __ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, satb_q_buf_byte_offset, tmp2);
- __ sub(tmp, oopSize, tmp);
-
- __ st_ptr(pre_val, tmp2, tmp); // [_buf + index] :=
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(tmp, G2_thread, satb_q_index_byte_offset);
-
- __ bind(refill);
-
- __ save_live_registers_no_oop_map(true);
-
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address,
- G1SATBMarkQueueSet::handle_zero_index_for_thread),
- G2_thread);
-
- __ restore_live_registers(true);
-
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ epilogue();
-}
-
-void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
- __ prologue("g1_post_barrier", false);
-
- G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set());
-
- Register addr = G4;
- Register cardtable = G5;
- Register tmp = G1_scratch;
- Register tmp2 = G3_scratch;
- CardTable::CardValue* byte_map_base = bs->card_table()->byte_map_base();
-
- Label not_already_dirty, restart, refill, young_card;
-
-#ifdef _LP64
- __ srlx(addr, CardTable::card_shift, addr);
-#else
- __ srl(addr, CardTable::card_shift, addr);
-#endif
-
- AddressLiteral rs((address)byte_map_base);
- __ set(rs, cardtable); // cardtable :=
- __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable]
-
- __ cmp_and_br_short(tmp, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card);
-
- __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
- __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable]
-
- assert(G1CardTable::dirty_card_val() == 0, "otherwise check this code");
- __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
-
- __ bind(young_card);
- // We didn't take the branch, so we're already dirty: return.
- // Use return-from-leaf
- __ retl();
- __ delayed()->nop();
-
- // Not dirty.
- __ bind(not_already_dirty);
-
- // Get cardtable + tmp into a reg by itself
- __ add(addr, cardtable, tmp2);
-
- // First, dirty it.
- __ stb(G0, tmp2, 0); // [cardPtr] := 0 (i.e., dirty).
-
- Register tmp3 = cardtable;
- Register tmp4 = tmp;
-
- // these registers are now dead
- addr = cardtable = tmp = noreg;
-
- int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
- int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
-
- __ bind(restart);
-
- // Get the index into the update buffer. G1DirtyCardQueue::_index is
- // a size_t so ld_ptr is appropriate here.
- __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3);
-
- // index == 0?
- __ cmp_and_brx_short(tmp3, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, tmp4);
- __ sub(tmp3, oopSize, tmp3);
-
- __ st_ptr(tmp2, tmp4, tmp3); // [_buf + index] :=
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(tmp3, G2_thread, dirty_card_q_index_byte_offset);
-
- __ bind(refill);
-
- __ save_live_registers_no_oop_map(true);
-
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address,
- G1DirtyCardQueueSet::handle_zero_index_for_thread),
- G2_thread);
-
- __ restore_live_registers(true);
-
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ epilogue();
-}
-
-#undef __
-
-#endif // COMPILER1
diff --git a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp
deleted file mode 100644
index 3c706b5e53a..00000000000
--- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_GC_G1_G1BARRIERSETASSEMBLER_SPARC_HPP
-#define CPU_SPARC_GC_G1_G1BARRIERSETASSEMBLER_SPARC_HPP
-
-#include "asm/macroAssembler.hpp"
-#include "gc/shared/modRefBarrierSetAssembler.hpp"
-#include "utilities/macros.hpp"
-
-class LIR_Assembler;
-class StubAssembler;
-class G1PreBarrierStub;
-class G1PostBarrierStub;
-
-class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
-protected:
- virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count);
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp);
-
- void g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs);
- void g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp);
-
- virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp);
-
-public:
-#ifdef COMPILER1
- void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
- void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
-
- void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
- void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
-#endif
-
- virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Address src, Register dst, Register tmp);
- virtual void barrier_stubs_init();
-};
-
-#endif // CPU_SPARC_GC_G1_G1BARRIERSETASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp
deleted file mode 100644
index c99d370aa93..00000000000
--- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/barrierSetAssembler.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "runtime/jniHandles.hpp"
-
-#define __ masm->
-
-void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp) {
- bool in_heap = (decorators & IN_HEAP) != 0;
- bool in_native = (decorators & IN_NATIVE) != 0;
- bool is_not_null = (decorators & IS_NOT_NULL) != 0;
-
- switch (type) {
- case T_ARRAY:
- case T_OBJECT: {
- if (in_heap) {
- if (dst.has_disp() && !Assembler::is_simm13(dst.disp())) {
- assert(!dst.has_index(), "not supported yet");
- __ set(dst.disp(), tmp);
- dst = Address(dst.base(), tmp);
- }
- if (UseCompressedOops) {
- assert(dst.base() != val, "not enough registers");
- if (is_not_null) {
- __ encode_heap_oop_not_null(val);
- } else {
- __ encode_heap_oop(val);
- }
- __ st(val, dst);
- } else {
- __ st_ptr(val, dst);
- }
- } else {
- assert(in_native, "why else?");
- __ st_ptr(val, dst);
- }
- break;
- }
- default: Unimplemented();
- }
-}
-
-void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Address src, Register dst, Register tmp) {
- bool in_heap = (decorators & IN_HEAP) != 0;
- bool in_native = (decorators & IN_NATIVE) != 0;
- bool is_not_null = (decorators & IS_NOT_NULL) != 0;
-
- switch (type) {
- case T_ARRAY:
- case T_OBJECT: {
- if (in_heap) {
- if (src.has_disp() && !Assembler::is_simm13(src.disp())) {
- assert(!src.has_index(), "not supported yet");
- __ set(src.disp(), tmp);
- src = Address(src.base(), tmp);
- }
- if (UseCompressedOops) {
- __ lduw(src, dst);
- if (is_not_null) {
- __ decode_heap_oop_not_null(dst);
- } else {
- __ decode_heap_oop(dst);
- }
- } else {
- __ ld_ptr(src, dst);
- }
- } else {
- assert(in_native, "why else?");
- __ ld_ptr(src, dst);
- }
- break;
- }
- default: Unimplemented();
- }
-}
-
-void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
- Register obj, Register tmp, Label& slowpath) {
- __ andn(obj, JNIHandles::weak_tag_mask, obj);
- __ ld_ptr(obj, 0, obj);
-}
diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp
deleted file mode 100644
index 0e91b042e66..00000000000
--- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_GC_SHARED_BARRIERSETASSEMBLER_SPARC_HPP
-#define CPU_SPARC_GC_SHARED_BARRIERSETASSEMBLER_SPARC_HPP
-
-#include "asm/macroAssembler.hpp"
-#include "memory/allocation.hpp"
-#include "oops/access.hpp"
-
-class InterpreterMacroAssembler;
-
-class BarrierSetAssembler: public CHeapObj {
-public:
- virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register src, Register dst, Register count) {}
- virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register src, Register dst, Register count) {}
-
- virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register src, Address dst, Register tmp);
-
- virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Address src, Register dst, Register tmp);
-
- // Support for jniFastGetField to try resolving a jobject/jweak in native
- virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
- Register obj, Register tmp, Label& slowpath);
-
- virtual void barrier_stubs_init() {}
-};
-
-#endif // CPU_SPARC_GC_SHARED_BARRIERSETASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp
deleted file mode 100644
index a0361ddc2f4..00000000000
--- a/src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/barrierSetNMethod.hpp"
-#include "utilities/debug.hpp"
-
-void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
- ShouldNotReachHere();
-}
-
-void BarrierSetNMethod::disarm(nmethod* nm) {
- ShouldNotReachHere();
-}
-
-bool BarrierSetNMethod::is_armed(nmethod* nm) {
- ShouldNotReachHere();
- return false;
-}
diff --git a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp
deleted file mode 100644
index 37565ad7d0d..00000000000
--- a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/barrierSet.hpp"
-#include "gc/shared/cardTable.hpp"
-#include "gc/shared/cardTableBarrierSet.hpp"
-#include "gc/shared/cardTableBarrierSetAssembler.hpp"
-#include "interpreter/interp_masm.hpp"
-
-#define __ masm->
-
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) /* nothing */
-#else
-#define BLOCK_COMMENT(str) __ block_comment(str)
-#endif
-
-#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
-
-void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count, Register tmp) {
- CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set());
- CardTable* ct = ctbs->card_table();
- assert_different_registers(addr, count, tmp);
-
- Label L_loop, L_done;
-
- __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_done); // zero count - nothing to do
-
- __ sll_ptr(count, LogBytesPerHeapOop, count);
- __ sub(count, BytesPerHeapOop, count);
- __ add(count, addr, count);
- // Use two shifts to clear out those low order two bits! (Cannot opt. into 1.)
- __ srl_ptr(addr, CardTable::card_shift, addr);
- __ srl_ptr(count, CardTable::card_shift, count);
- __ sub(count, addr, count);
- AddressLiteral rs(ct->byte_map_base());
- __ set(rs, tmp);
- __ BIND(L_loop);
- __ stb(G0, tmp, addr);
- __ subcc(count, 1, count);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
- __ delayed()->add(addr, 1, addr);
-
- __ BIND(L_done);
-}
-
-void CardTableBarrierSetAssembler::card_table_write(MacroAssembler* masm,
- CardTable::CardValue* byte_map_base,
- Register tmp, Register obj) {
- __ srlx(obj, CardTable::card_shift, obj);
- assert(tmp != obj, "need separate temp reg");
- __ set((address) byte_map_base, tmp);
- __ stb(G0, tmp, obj);
-}
-
-void CardTableBarrierSetAssembler::card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) {
- // If we're writing constant NULL, we can skip the write barrier.
- if (new_val == G0) return;
- CardTableBarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set());
- card_table_write(masm, bs->card_table()->byte_map_base(), tmp, store_addr);
-}
-
-void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp) {
- bool in_heap = (decorators & IN_HEAP) != 0;
-
- bool is_array = (decorators & IS_ARRAY) != 0;
- bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
- bool precise = is_array || on_anonymous;
-
- // No need for post barrier if storing NULL
- bool needs_post_barrier = val != G0 && in_heap;
-
- BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp);
- if (needs_post_barrier) {
- Register base = dst.base();
- if (precise) {
- if (!dst.has_index()) {
- __ add(base, dst.disp(), base);
- } else {
- assert(!dst.has_disp(), "not supported yet");
- __ add(base, dst.index(), base);
- }
- }
- card_write_barrier_post(masm, base, val, tmp);
- }
-}
diff --git a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp
deleted file mode 100644
index 0166006f16b..00000000000
--- a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SPARC_HPP
-#define CPU_SPARC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SPARC_HPP
-
-#include "asm/macroAssembler.hpp"
-#include "gc/shared/cardTable.hpp"
-#include "gc/shared/modRefBarrierSetAssembler.hpp"
-
-class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler {
-protected:
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count, Register tmp);
-
- void card_table_write(MacroAssembler* masm, CardTable::CardValue* byte_map_base, Register tmp, Register obj);
-
- void card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp);
-
- virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp);
-};
-
-#endif // CPU_SPARC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp
deleted file mode 100644
index 57b51c0cf21..00000000000
--- a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/modRefBarrierSetAssembler.hpp"
-
-#define __ masm->
-
-void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register src, Register dst, Register count) {
- if (type == T_OBJECT) {
- bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
- if (!checkcast) {
- // save arguments for barrier generation
- __ mov(dst, G1);
- __ mov(count, G5);
- gen_write_ref_array_pre_barrier(masm, decorators, G1, G5);
- } else {
- gen_write_ref_array_pre_barrier(masm, decorators, dst, count);
- }
- }
-}
-
-void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register src, Register dst, Register count) {
- if (type == T_OBJECT) {
- bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0;
- if (!checkcast) {
- // O0 is used as temp register
- gen_write_ref_array_post_barrier(masm, decorators, G1, G5, O0);
- } else {
- gen_write_ref_array_post_barrier(masm, decorators, dst, count, O3);
- }
- }
-}
-
-void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp) {
- if (is_reference_type(type)) {
- oop_store_at(masm, decorators, type, val, dst, tmp);
- } else {
- BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp);
- }
-}
diff --git a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp
deleted file mode 100644
index 80e9686a212..00000000000
--- a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_GC_SHARED_MODREFBARRIERSETASSEMBLER_SPARC_HPP
-#define CPU_SPARC_GC_SHARED_MODREFBARRIERSETASSEMBLER_SPARC_HPP
-
-#include "asm/macroAssembler.hpp"
-#include "gc/shared/barrierSetAssembler.hpp"
-
-// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other
-// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
-// accesses, which are overridden in the concrete BarrierSetAssembler.
-
-class ModRefBarrierSetAssembler: public BarrierSetAssembler {
-protected:
- virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count) {}
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count, Register tmp) {}
-
- virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp) = 0;
-public:
- virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register src, Register dst, Register count);
- virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register src, Register dst, Register count);
-
- virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register val, Address dst, Register tmp);
-};
-
-#endif // CPU_SPARC_GC_SHARED_MODREFBARRIERSETASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp b/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp
deleted file mode 100644
index 0bbdfe264ed..00000000000
--- a/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_GLOBALDEFINITIONS_SPARC_HPP
-#define CPU_SPARC_GLOBALDEFINITIONS_SPARC_HPP
-
-// Size of Sparc Instructions
-const int BytesPerInstWord = 4;
-
-const int StackAlignmentInBytes = (2*wordSize);
-
-// Indicates whether the C calling conventions require that
-// 32-bit integer argument values are extended to 64 bits.
-const bool CCallingConventionRequiresIntsAsLongs = true;
-
-#define SUPPORTS_NATIVE_CX8
-
-#define CPU_MULTI_COPY_ATOMIC
-
-// The expected size in bytes of a cache line, used to pad data structures.
-#if defined(TIERED)
- // tiered, 64-bit, large machine
- #define DEFAULT_CACHE_LINE_SIZE 128
- #define OM_CACHE_LINE_SIZE 64
-#elif defined(COMPILER1)
- // pure C1, 32-bit, small machine
- #define DEFAULT_CACHE_LINE_SIZE 16
-#elif defined(COMPILER2)
- // pure C2, 64-bit, large machine
- #define DEFAULT_CACHE_LINE_SIZE 128
- #define OM_CACHE_LINE_SIZE 64
-#endif
-
-#if defined(SOLARIS)
-#define SUPPORT_RESERVED_STACK_AREA
-#endif
-
-#define COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS true
-
-#endif // CPU_SPARC_GLOBALDEFINITIONS_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/globals_sparc.hpp b/src/hotspot/cpu/sparc/globals_sparc.hpp
deleted file mode 100644
index c8a4400e3d7..00000000000
--- a/src/hotspot/cpu/sparc/globals_sparc.hpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_GLOBALS_SPARC_HPP
-#define CPU_SPARC_GLOBALS_SPARC_HPP
-
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
-
-// Sets the default values for platform dependent flags used by the runtime system.
-// (see globals.hpp)
-
-// For sparc we do not do call backs when a thread is in the interpreter, because the
-// interpreter dispatch needs at least two instructions - first to load the dispatch address
-// in a register, and second to jmp. The swapping of the dispatch table may occur _after_
-// the load of the dispatch address and hence the jmp would still go to the location
-// according to the prior table. So, we let the thread continue and let it block by itself.
-define_pd_global(bool, DontYieldALot, true); // yield no more than 100 times per second
-
-define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
-define_pd_global(bool, TrapBasedNullChecks, false); // Not needed on sparc.
-define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs passed to check cast
-
-define_pd_global(uintx, CodeCacheSegmentSize, 64 TIERED_ONLY(+64)); // Tiered compilation has large code-entry alignment.
-define_pd_global(intx, CodeEntryAlignment, 32);
-// The default setting 16/16 seems to work best.
-// (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.)
-define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize
-define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC
-define_pd_global(intx, InlineSmallCode, 1500);
-
-#define DEFAULT_STACK_YELLOW_PAGES (2)
-#define DEFAULT_STACK_RED_PAGES (1)
-#define DEFAULT_STACK_RESERVED_PAGES (SOLARIS_ONLY(1) NOT_SOLARIS(0))
-
-define_pd_global(intx, CompilerThreadStackSize, 1024);
-define_pd_global(intx, ThreadStackSize, 1024);
-define_pd_global(intx, VMThreadStackSize, 1024);
-#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2))
-
-#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
-#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
-#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES
-#define MIN_STACK_RESERVED_PAGES (0)
-
-define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES);
-define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES);
-define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES);
-define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES);
-
-define_pd_global(bool, RewriteBytecodes, true);
-define_pd_global(bool, RewriteFrequentPairs, true);
-
-define_pd_global(bool, PreserveFramePointer, false);
-
-define_pd_global(uintx, TypeProfileLevel, 111);
-
-define_pd_global(bool, CompactStrings, true);
-
-define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
-
-#define ARCH_FLAGS(develop, \
- product, \
- diagnostic, \
- experimental, \
- notproduct, \
- range, \
- constraint) \
- \
- product(intx, UseVIS, 99, \
- "Highest supported VIS instructions set on SPARC") \
- range(0, 99) \
- \
- product(bool, UseCBCond, false, \
- "Use compare and branch instruction on SPARC") \
- \
- product(bool, UseMPMUL, false, \
- "Use multi-precision multiply instruction (mpmul) on SPARC") \
- \
- product(bool, UseBlockZeroing, false, \
- "Use special cpu instructions for block zeroing") \
- \
- product(intx, BlockZeroingLowLimit, 2048, \
- "Minimum size in bytes when block zeroing will be used") \
- range(1, max_jint) \
- \
- product(bool, UseBlockCopy, false, \
- "Use special cpu instructions for block copy") \
- \
- product(intx, BlockCopyLowLimit, 2048, \
- "Minimum size in bytes when block copy will be used") \
- range(1, max_jint) \
- \
- product(bool, UseNiagaraInstrs, false, \
- "Use Niagara-efficient instruction subset") \
- \
- develop(bool, UseCASForSwap, false, \
- "Do not use swap instructions, but only CAS (in a loop) on SPARC")\
- \
- product(uintx, ArraycopySrcPrefetchDistance, 0, \
- "Distance to prefetch source array in arraycopy") \
- constraint(ArraycopySrcPrefetchDistanceConstraintFunc, AfterErgo) \
- \
- product(uintx, ArraycopyDstPrefetchDistance, 0, \
- "Distance to prefetch destination array in arraycopy") \
- constraint(ArraycopyDstPrefetchDistanceConstraintFunc, AfterErgo) \
-
-#endif // CPU_SPARC_GLOBALS_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/icBuffer_sparc.cpp b/src/hotspot/cpu/sparc/icBuffer_sparc.cpp
deleted file mode 100644
index 5b384514489..00000000000
--- a/src/hotspot/cpu/sparc/icBuffer_sparc.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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_sparc.hpp"
-#include "oops/oop.inline.hpp"
-
-int InlineCacheBuffer::ic_stub_code_size() {
- return (NativeMovConstReg::instruction_size + // sethi;add
- NativeJump::instruction_size + // sethi; jmp; delay slot
- (1*BytesPerInstWord) + 1); // flush + 1 extra byte
-}
-
-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 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
- AddressLiteral cached_value_addrlit((address)cached_value, relocInfo::none);
- // Force the set to generate the fixed sequence so next_instruction_address works
- masm->patchable_set(cached_value_addrlit, G5_inline_cache_reg);
- assert(G3_scratch != G5_method, "Do not clobber the method oop in the transition stub");
- assert(G3_scratch != G5_inline_cache_reg, "Do not clobber the inline cache register in the transition stub");
- AddressLiteral entry(entry_point);
- masm->JUMP(entry, G3_scratch, 0);
- masm->delayed()->nop();
- masm->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
- NativeJump* jump = nativeJump_at(move->next_instruction_address());
- void* o = (void*)move->data();
- return o;
-}
diff --git a/src/hotspot/cpu/sparc/icache_sparc.cpp b/src/hotspot/cpu/sparc/icache_sparc.cpp
deleted file mode 100644
index 01914de00b4..00000000000
--- a/src/hotspot/cpu/sparc/icache_sparc.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "runtime/icache.hpp"
-
-#define __ _masm->
-
-void ICacheStubGenerator::generate_icache_flush(
- ICache::flush_icache_stub_t* flush_icache_stub
-) {
- StubCodeMark mark(this, "ICache", "flush_icache_stub");
- address start = __ pc();
-
- Label L;
- __ bind(L);
- __ flush( O0, G0 );
- __ deccc( O1 );
- __ br(Assembler::positive, false, Assembler::pn, L);
- __ delayed()->inc( O0, 8 );
- __ retl(false);
- __ delayed()->mov( O2, O0 ); // handshake with caller to make sure it happened!
-
- // Must be set here so StubCodeMark destructor can call the flush stub.
- *flush_icache_stub = (ICache::flush_icache_stub_t)start;
-};
-
-#undef __
diff --git a/src/hotspot/cpu/sparc/icache_sparc.hpp b/src/hotspot/cpu/sparc/icache_sparc.hpp
deleted file mode 100644
index 7d3feea4a95..00000000000
--- a/src/hotspot/cpu/sparc/icache_sparc.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_ICACHE_SPARC_HPP
-#define CPU_SPARC_ICACHE_SPARC_HPP
-
-// Interface for updating the instruction cache. Whenever the VM modifies
-// code, part of the processor instruction cache potentially has to be flushed.
-
-
-class ICache : public AbstractICache {
- public:
- enum {
- stub_size = 160, // Size of the icache flush stub in bytes
- line_size = 8, // flush instruction affects a dword
- log2_line_size = 3 // log2(line_size)
- };
-
- // Use default implementation
-};
-
-#endif // CPU_SPARC_ICACHE_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp b/src/hotspot/cpu/sparc/interp_masm_sparc.cpp
deleted file mode 100644
index cd7938f21a6..00000000000
--- a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp
+++ /dev/null
@@ -1,2650 +0,0 @@
-/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "asm/macroAssembler.inline.hpp"
-#include "interp_masm_sparc.hpp"
-#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "logging/log.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/markWord.hpp"
-#include "oops/methodData.hpp"
-#include "oops/method.hpp"
-#include "oops/methodCounters.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiThreadState.hpp"
-#include "runtime/basicLock.hpp"
-#include "runtime/biasedLocking.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/safepointMechanism.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/thread.inline.hpp"
-#include "utilities/align.hpp"
-#include "utilities/powerOfTwo.hpp"
-
-// Implementation of InterpreterMacroAssembler
-
-// This file specializes the assember with interpreter-specific macros
-
-const Address InterpreterMacroAssembler::l_tmp(FP, (frame::interpreter_frame_l_scratch_fp_offset * wordSize) + STACK_BIAS);
-const Address InterpreterMacroAssembler::d_tmp(FP, (frame::interpreter_frame_d_scratch_fp_offset * wordSize) + STACK_BIAS);
-
-void InterpreterMacroAssembler::jump_to_entry(address entry) {
- assert(entry, "Entry must have been generated by now");
- AddressLiteral al(entry);
- jump_to(al, G3_scratch);
- delayed()->nop();
-}
-
-void InterpreterMacroAssembler::compute_extra_locals_size_in_bytes(Register args_size, Register locals_size, Register delta) {
- // Note: this algorithm is also used by C1's OSR entry sequence.
- // Any changes should also be applied to CodeEmitter::emit_osr_entry().
- assert_different_registers(args_size, locals_size);
- // max_locals*2 for TAGS. Assumes that args_size has already been adjusted.
- subcc(locals_size, args_size, delta);// extra space for non-arguments locals in words
- // Use br/mov combination because it works on both V8 and V9 and is
- // faster.
- Label skip_move;
- br(Assembler::negative, true, Assembler::pt, skip_move);
- delayed()->mov(G0, delta);
- bind(skip_move);
- align_up(delta, WordsPerLong); // make multiple of 2 (SP must be 2-word aligned)
- sll(delta, LogBytesPerWord, delta); // extra space for locals in bytes
-}
-
-// Dispatch code executed in the prolog of a bytecode which does not do it's
-// own dispatch. The dispatch address is computed and placed in IdispatchAddress
-void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) {
- assert_not_delayed();
- ldub( Lbcp, bcp_incr, Lbyte_code); // load next bytecode
- // dispatch table to use
- AddressLiteral tbl(Interpreter::dispatch_table(state));
- sll(Lbyte_code, LogBytesPerWord, Lbyte_code); // multiply by wordSize
- set(tbl, G3_scratch); // compute addr of table
- ld_ptr(G3_scratch, Lbyte_code, IdispatchAddress); // get entry addr
-}
-
-
-// Dispatch code executed in the epilog of a bytecode which does not do it's
-// own dispatch. The dispatch address in IdispatchAddress is used for the
-// dispatch.
-void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) {
- assert_not_delayed();
- interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
- jmp( IdispatchAddress, 0 );
- if (bcp_incr != 0) delayed()->inc(Lbcp, bcp_incr);
- else delayed()->nop();
-}
-
-void InterpreterMacroAssembler::dispatch_next(TosState state, int bcp_incr, bool generate_poll) {
- // %%%% consider branching to a single shared dispatch stub (for each bcp_incr)
- assert_not_delayed();
- ldub( Lbcp, bcp_incr, Lbyte_code); // load next bytecode
- dispatch_Lbyte_code(state, Interpreter::dispatch_table(state), bcp_incr, true, generate_poll);
-}
-
-
-void InterpreterMacroAssembler::dispatch_next_noverify_oop(TosState state, int bcp_incr) {
- // %%%% consider branching to a single shared dispatch stub (for each bcp_incr)
- assert_not_delayed();
- ldub( Lbcp, bcp_incr, Lbyte_code); // load next bytecode
- dispatch_Lbyte_code(state, Interpreter::dispatch_table(state), bcp_incr, false);
-}
-
-
-void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) {
- // load current bytecode
- assert_not_delayed();
- ldub( Lbcp, 0, Lbyte_code); // load next bytecode
- dispatch_base(state, table);
-}
-
-
-void InterpreterMacroAssembler::call_VM_leaf_base(
- Register java_thread,
- address entry_point,
- int number_of_arguments
-) {
- if (!java_thread->is_valid())
- java_thread = L7_thread_cache;
- // super call
- MacroAssembler::call_VM_leaf_base(java_thread, entry_point, number_of_arguments);
-}
-
-
-void InterpreterMacroAssembler::call_VM_base(
- Register oop_result,
- Register java_thread,
- Register last_java_sp,
- address entry_point,
- int number_of_arguments,
- bool check_exception
-) {
- if (!java_thread->is_valid())
- java_thread = L7_thread_cache;
- // See class ThreadInVMfromInterpreter, which assumes that the interpreter
- // takes responsibility for setting its own thread-state on call-out.
- // However, ThreadInVMfromInterpreter resets the state to "in_Java".
-
- //save_bcp(); // save bcp
- MacroAssembler::call_VM_base(oop_result, java_thread, last_java_sp, entry_point, number_of_arguments, check_exception);
- //restore_bcp(); // restore bcp
- //restore_locals(); // restore locals pointer
-}
-
-
-void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) {
- if (JvmtiExport::can_pop_frame()) {
- Label L;
-
- // Check the "pending popframe condition" flag in the current thread
- ld(G2_thread, JavaThread::popframe_condition_offset(), scratch_reg);
-
- // Initiate popframe handling only if it is not already being processed. If the flag
- // has the popframe_processing bit set, it means that this code is called *during* popframe
- // handling - we don't want to reenter.
- btst(JavaThread::popframe_pending_bit, scratch_reg);
- br(zero, false, pt, L);
- delayed()->nop();
- btst(JavaThread::popframe_processing_bit, scratch_reg);
- br(notZero, false, pt, L);
- delayed()->nop();
-
- // Call Interpreter::remove_activation_preserving_args_entry() to get the
- // address of the same-named entrypoint in the generated interpreter code.
- call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry));
-
- // Jump to Interpreter::_remove_activation_preserving_args_entry
- jmpl(O0, G0, G0);
- delayed()->nop();
- bind(L);
- }
-}
-
-
-void InterpreterMacroAssembler::load_earlyret_value(TosState state) {
- Register thr_state = G4_scratch;
- ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), thr_state);
- const Address tos_addr(thr_state, JvmtiThreadState::earlyret_tos_offset());
- const Address oop_addr(thr_state, JvmtiThreadState::earlyret_oop_offset());
- const Address val_addr(thr_state, JvmtiThreadState::earlyret_value_offset());
- switch (state) {
- case ltos: ld_long(val_addr, Otos_l); break;
- case atos: ld_ptr(oop_addr, Otos_l);
- st_ptr(G0, oop_addr); break;
- case btos: // fall through
- case ztos: // fall through
- case ctos: // fall through
- case stos: // fall through
- case itos: ld(val_addr, Otos_l1); break;
- case ftos: ldf(FloatRegisterImpl::S, val_addr, Ftos_f); break;
- case dtos: ldf(FloatRegisterImpl::D, val_addr, Ftos_d); break;
- case vtos: /* nothing to do */ break;
- default : ShouldNotReachHere();
- }
- // Clean up tos value in the jvmti thread state
- or3(G0, ilgl, G3_scratch);
- stw(G3_scratch, tos_addr);
- st_long(G0, val_addr);
- interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
-}
-
-
-void InterpreterMacroAssembler::check_and_handle_earlyret(Register scratch_reg) {
- if (JvmtiExport::can_force_early_return()) {
- Label L;
- Register thr_state = G3_scratch;
- ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), thr_state);
- br_null_short(thr_state, pt, L); // if (thread->jvmti_thread_state() == NULL) exit;
-
- // Initiate earlyret handling only if it is not already being processed.
- // If the flag has the earlyret_processing bit set, it means that this code
- // is called *during* earlyret handling - we don't want to reenter.
- ld(thr_state, JvmtiThreadState::earlyret_state_offset(), G4_scratch);
- cmp_and_br_short(G4_scratch, JvmtiThreadState::earlyret_pending, Assembler::notEqual, pt, L);
-
- // Call Interpreter::remove_activation_early_entry() to get the address of the
- // same-named entrypoint in the generated interpreter code
- ld(thr_state, JvmtiThreadState::earlyret_tos_offset(), Otos_l1);
- call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), Otos_l1);
-
- // Jump to Interpreter::_remove_activation_early_entry
- jmpl(O0, G0, G0);
- delayed()->nop();
- bind(L);
- }
-}
-
-
-void InterpreterMacroAssembler::super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) {
- mov(arg_1, O0);
- mov(arg_2, O1);
- MacroAssembler::call_VM_leaf_base(thread_cache, entry_point, 2);
-}
-
-void InterpreterMacroAssembler::dispatch_base(TosState state, address* table) {
- assert_not_delayed();
- dispatch_Lbyte_code(state, table);
-}
-
-
-void InterpreterMacroAssembler::dispatch_normal(TosState state) {
- dispatch_base(state, Interpreter::normal_table(state));
-}
-
-
-void InterpreterMacroAssembler::dispatch_only(TosState state) {
- dispatch_base(state, Interpreter::dispatch_table(state));
-}
-
-
-// common code to dispatch and dispatch_only
-// dispatch value in Lbyte_code and increment Lbcp
-
-void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, address* table, int bcp_incr, bool verify, bool generate_poll) {
- // %%%%% maybe implement +VerifyActivationFrameSize here
- //verify_thread(); //too slow; we will just verify on method entry & exit
- if (verify) interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
- // dispatch table to use
- AddressLiteral tbl(table);
- Label dispatch;
-
- if (generate_poll) {
- AddressLiteral sfpt_tbl(Interpreter::safept_table(state));
- Label no_safepoint;
-
- if (tbl.value() != sfpt_tbl.value()) {
- ldx(Address(G2_thread, Thread::polling_page_offset()), G3_scratch, 0);
- // Armed page has poll_bit set, if poll bit is cleared just continue.
- and3(G3_scratch, SafepointMechanism::poll_bit(), G3_scratch);
-
- br_null_short(G3_scratch, Assembler::pt, no_safepoint);
- set(sfpt_tbl, G3_scratch);
- ba_short(dispatch);
- }
- bind(no_safepoint);
- }
-
- set(tbl, G3_scratch); // compute addr of table
- bind(dispatch);
- sll(Lbyte_code, LogBytesPerWord, Lbyte_code); // multiply by wordSize
- ld_ptr(G3_scratch, Lbyte_code, G3_scratch); // get entry addr
- jmp( G3_scratch, 0 );
- if (bcp_incr != 0) delayed()->inc(Lbcp, bcp_incr);
- else delayed()->nop();
-}
-
-
-// Helpers for expression stack
-
-// Longs and doubles are Category 2 computational types in the
-// JVM specification (section 3.11.1) and take 2 expression stack or
-// local slots.
-// Aligning them on 32 bit with tagged stacks is hard because the code generated
-// for the dup* bytecodes depends on what types are already on the stack.
-// If the types are split into the two stack/local slots, that is much easier
-// (and we can use 0 for non-reference tags).
-
-// Known good alignment in _LP64 but unknown otherwise
-void InterpreterMacroAssembler::load_unaligned_double(Register r1, int offset, FloatRegister d) {
- assert_not_delayed();
-
- ldf(FloatRegisterImpl::D, r1, offset, d);
-}
-
-// Known good alignment in _LP64 but unknown otherwise
-void InterpreterMacroAssembler::store_unaligned_double(FloatRegister d, Register r1, int offset) {
- assert_not_delayed();
-
- stf(FloatRegisterImpl::D, d, r1, offset);
- // store something more useful here
- debug_only(stx(G0, r1, offset+Interpreter::stackElementSize);)
-}
-
-
-// Known good alignment in _LP64 but unknown otherwise
-void InterpreterMacroAssembler::load_unaligned_long(Register r1, int offset, Register rd) {
- assert_not_delayed();
- ldx(r1, offset, rd);
-}
-
-// Known good alignment in _LP64 but unknown otherwise
-void InterpreterMacroAssembler::store_unaligned_long(Register l, Register r1, int offset) {
- assert_not_delayed();
-
- stx(l, r1, offset);
- // store something more useful here
- stx(G0, r1, offset+Interpreter::stackElementSize);
-}
-
-void InterpreterMacroAssembler::pop_i(Register r) {
- assert_not_delayed();
- ld(Lesp, Interpreter::expr_offset_in_bytes(0), r);
- inc(Lesp, Interpreter::stackElementSize);
- debug_only(verify_esp(Lesp));
-}
-
-void InterpreterMacroAssembler::pop_ptr(Register r, Register scratch) {
- assert_not_delayed();
- ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), r);
- inc(Lesp, Interpreter::stackElementSize);
- debug_only(verify_esp(Lesp));
-}
-
-void InterpreterMacroAssembler::pop_l(Register r) {
- assert_not_delayed();
- load_unaligned_long(Lesp, Interpreter::expr_offset_in_bytes(0), r);
- inc(Lesp, 2*Interpreter::stackElementSize);
- debug_only(verify_esp(Lesp));
-}
-
-
-void InterpreterMacroAssembler::pop_f(FloatRegister f, Register scratch) {
- assert_not_delayed();
- ldf(FloatRegisterImpl::S, Lesp, Interpreter::expr_offset_in_bytes(0), f);
- inc(Lesp, Interpreter::stackElementSize);
- debug_only(verify_esp(Lesp));
-}
-
-
-void InterpreterMacroAssembler::pop_d(FloatRegister f, Register scratch) {
- assert_not_delayed();
- load_unaligned_double(Lesp, Interpreter::expr_offset_in_bytes(0), f);
- inc(Lesp, 2*Interpreter::stackElementSize);
- debug_only(verify_esp(Lesp));
-}
-
-
-void InterpreterMacroAssembler::push_i(Register r) {
- assert_not_delayed();
- debug_only(verify_esp(Lesp));
- st(r, Lesp, 0);
- dec(Lesp, Interpreter::stackElementSize);
-}
-
-void InterpreterMacroAssembler::push_ptr(Register r) {
- assert_not_delayed();
- st_ptr(r, Lesp, 0);
- dec(Lesp, Interpreter::stackElementSize);
-}
-
-// remember: our convention for longs in SPARC is:
-// O0 (Otos_l1) has high-order part in first word,
-// O1 (Otos_l2) has low-order part in second word
-
-void InterpreterMacroAssembler::push_l(Register r) {
- assert_not_delayed();
- debug_only(verify_esp(Lesp));
- // Longs are stored in memory-correct order, even if unaligned.
- int offset = -Interpreter::stackElementSize;
- store_unaligned_long(r, Lesp, offset);
- dec(Lesp, 2 * Interpreter::stackElementSize);
-}
-
-
-void InterpreterMacroAssembler::push_f(FloatRegister f) {
- assert_not_delayed();
- debug_only(verify_esp(Lesp));
- stf(FloatRegisterImpl::S, f, Lesp, 0);
- dec(Lesp, Interpreter::stackElementSize);
-}
-
-
-void InterpreterMacroAssembler::push_d(FloatRegister d) {
- assert_not_delayed();
- debug_only(verify_esp(Lesp));
- // Longs are stored in memory-correct order, even if unaligned.
- int offset = -Interpreter::stackElementSize;
- store_unaligned_double(d, Lesp, offset);
- dec(Lesp, 2 * Interpreter::stackElementSize);
-}
-
-
-void InterpreterMacroAssembler::push(TosState state) {
- interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
- switch (state) {
- case atos: push_ptr(); break;
- case btos: // fall through
- case ztos: // fall through
- case ctos: // fall through
- case stos: // fall through
- case itos: push_i(); break;
- case ltos: push_l(); break;
- case ftos: push_f(); break;
- case dtos: push_d(); break;
- case vtos: /* nothing to do */ break;
- default : ShouldNotReachHere();
- }
-}
-
-
-void InterpreterMacroAssembler::pop(TosState state) {
- switch (state) {
- case atos: pop_ptr(); break;
- case btos: // fall through
- case ztos: // fall through
- case ctos: // fall through
- case stos: // fall through
- case itos: pop_i(); break;
- case ltos: pop_l(); break;
- case ftos: pop_f(); break;
- case dtos: pop_d(); break;
- case vtos: /* nothing to do */ break;
- default : ShouldNotReachHere();
- }
- interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
-}
-
-
-// Helpers for swap and dup
-void InterpreterMacroAssembler::load_ptr(int n, Register val) {
- ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(n), val);
-}
-void InterpreterMacroAssembler::store_ptr(int n, Register val) {
- st_ptr(val, Lesp, Interpreter::expr_offset_in_bytes(n));
-}
-
-
-void InterpreterMacroAssembler::load_receiver(Register param_count,
- Register recv) {
- sll(param_count, Interpreter::logStackElementSize, param_count);
- ld_ptr(Lesp, param_count, recv); // gets receiver oop
-}
-
-void InterpreterMacroAssembler::empty_expression_stack() {
- // Reset Lesp.
- sub( Lmonitors, wordSize, Lesp );
-
- // Reset SP by subtracting more space from Lesp.
- Label done;
- assert(G4_scratch != Gframe_size, "Only you can prevent register aliasing!");
-
- // A native does not need to do this, since its callee does not change SP.
- ld(Lmethod, Method::access_flags_offset(), Gframe_size); // Load access flags.
- btst(JVM_ACC_NATIVE, Gframe_size);
- br(Assembler::notZero, false, Assembler::pt, done);
- delayed()->nop();
-
- // Compute max expression stack+register save area
- ld_ptr(Lmethod, in_bytes(Method::const_offset()), Gframe_size);
- lduh(Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size); // Load max stack.
- add(Gframe_size, frame::memory_parameter_word_sp_offset+Method::extra_stack_entries(), Gframe_size );
-
- //
- // now set up a stack frame with the size computed above
- //
- //round_to( Gframe_size, WordsPerLong ); // -- moved down to the "and" below
- sll( Gframe_size, LogBytesPerWord, Gframe_size );
- sub( Lesp, Gframe_size, Gframe_size );
- and3( Gframe_size, -(2 * wordSize), Gframe_size ); // align SP (downwards) to an 8/16-byte boundary
- debug_only(verify_sp(Gframe_size, G4_scratch));
- sub(Gframe_size, STACK_BIAS, Gframe_size );
- mov(Gframe_size, SP);
-
- bind(done);
-}
-
-
-#ifdef ASSERT
-void InterpreterMacroAssembler::verify_sp(Register Rsp, Register Rtemp) {
- Label Bad, OK;
-
- // Saved SP must be aligned.
- btst(2*BytesPerWord-1, Rsp);
- br(Assembler::notZero, false, Assembler::pn, Bad);
- delayed()->nop();
-
- // Saved SP, plus register window size, must not be above FP.
- add(Rsp, frame::register_save_words * wordSize, Rtemp);
- sub(Rtemp, STACK_BIAS, Rtemp); // Bias Rtemp before cmp to FP
- cmp_and_brx_short(Rtemp, FP, Assembler::greaterUnsigned, Assembler::pn, Bad);
-
- // Saved SP must not be ridiculously below current SP.
- size_t maxstack = MAX2(JavaThread::stack_size_at_create(), (size_t) 4*K*K);
- set(maxstack, Rtemp);
- sub(SP, Rtemp, Rtemp);
- add(Rtemp, STACK_BIAS, Rtemp); // Unbias Rtemp before cmp to Rsp
- cmp_and_brx_short(Rsp, Rtemp, Assembler::lessUnsigned, Assembler::pn, Bad);
-
- ba_short(OK);
-
- bind(Bad);
- stop("on return to interpreted call, restored SP is corrupted");
-
- bind(OK);
-}
-
-
-void InterpreterMacroAssembler::verify_esp(Register Resp) {
- // about to read or write Resp[0]
- // make sure it is not in the monitors or the register save area
- Label OK1, OK2;
-
- cmp(Resp, Lmonitors);
- brx(Assembler::lessUnsigned, true, Assembler::pt, OK1);
- delayed()->sub(Resp, frame::memory_parameter_word_sp_offset * wordSize, Resp);
- stop("too many pops: Lesp points into monitor area");
- bind(OK1);
- sub(Resp, STACK_BIAS, Resp);
- cmp(Resp, SP);
- brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, OK2);
- delayed()->add(Resp, STACK_BIAS + frame::memory_parameter_word_sp_offset * wordSize, Resp);
- stop("too many pushes: Lesp points into register window");
- bind(OK2);
-}
-#endif // ASSERT
-
-// Load compiled (i2c) or interpreter entry when calling from interpreted and
-// do the call. Centralized so that all interpreter calls will do the same actions.
-// If jvmti single stepping is on for a thread we must not call compiled code.
-void InterpreterMacroAssembler::call_from_interpreter(Register target, Register scratch, Register Rret) {
-
- // Assume we want to go compiled if available
-
- ld_ptr(G5_method, in_bytes(Method::from_interpreted_offset()), target);
-
- if (JvmtiExport::can_post_interpreter_events()) {
- // JVMTI events, such as single-stepping, are implemented partly by avoiding running
- // compiled code in threads for which the event is enabled. Check here for
- // interp_only_mode if these events CAN be enabled.
- verify_thread();
- Label skip_compiled_code;
-
- const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset());
- ld(interp_only, scratch);
- cmp_zero_and_br(Assembler::notZero, scratch, skip_compiled_code, true, Assembler::pn);
- delayed()->ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), target);
- bind(skip_compiled_code);
- }
-
- // the i2c_adapters need Method* in G5_method (right? %%%)
- // do the call
-#ifdef ASSERT
- {
- Label ok;
- br_notnull_short(target, Assembler::pt, ok);
- stop("null entry point");
- bind(ok);
- }
-#endif // ASSERT
-
- // Adjust Rret first so Llast_SP can be same as Rret
- add(Rret, -frame::pc_return_offset, O7);
- add(Lesp, BytesPerWord, Gargs); // setup parameter pointer
- // Record SP so we can remove any stack space allocated by adapter transition
- jmp(target, 0);
- delayed()->mov(SP, Llast_SP);
-}
-
-void InterpreterMacroAssembler::if_cmp(Condition cc, bool ptr_compare) {
- assert_not_delayed();
-
- Label not_taken;
- if (ptr_compare) brx(cc, false, Assembler::pn, not_taken);
- else br (cc, false, Assembler::pn, not_taken);
- delayed()->nop();
-
- TemplateTable::branch(false,false);
-
- bind(not_taken);
-
- profile_not_taken_branch(G3_scratch);
-}
-
-
-void InterpreterMacroAssembler::get_2_byte_integer_at_bcp(
- int bcp_offset,
- Register Rtmp,
- Register Rdst,
- signedOrNot is_signed,
- setCCOrNot should_set_CC ) {
- assert(Rtmp != Rdst, "need separate temp register");
- assert_not_delayed();
- switch (is_signed) {
- default: ShouldNotReachHere();
-
- case Signed: ldsb( Lbcp, bcp_offset, Rdst ); break; // high byte
- case Unsigned: ldub( Lbcp, bcp_offset, Rdst ); break; // high byte
- }
- ldub( Lbcp, bcp_offset + 1, Rtmp ); // low byte
- sll( Rdst, BitsPerByte, Rdst);
- switch (should_set_CC ) {
- default: ShouldNotReachHere();
-
- case set_CC: orcc( Rdst, Rtmp, Rdst ); break;
- case dont_set_CC: or3( Rdst, Rtmp, Rdst ); break;
- }
-}
-
-
-void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(
- int bcp_offset,
- Register Rtmp,
- Register Rdst,
- setCCOrNot should_set_CC ) {
- assert(Rtmp != Rdst, "need separate temp register");
- assert_not_delayed();
- add( Lbcp, bcp_offset, Rtmp);
- andcc( Rtmp, 3, G0);
- Label aligned;
- switch (should_set_CC ) {
- default: ShouldNotReachHere();
-
- case set_CC: break;
- case dont_set_CC: break;
- }
-
- br(Assembler::zero, true, Assembler::pn, aligned);
- delayed()->ldsw(Rtmp, 0, Rdst);
-
- ldub(Lbcp, bcp_offset + 3, Rdst);
- ldub(Lbcp, bcp_offset + 2, Rtmp); sll(Rtmp, 8, Rtmp); or3(Rtmp, Rdst, Rdst);
- ldub(Lbcp, bcp_offset + 1, Rtmp); sll(Rtmp, 16, Rtmp); or3(Rtmp, Rdst, Rdst);
- ldsb(Lbcp, bcp_offset + 0, Rtmp); sll(Rtmp, 24, Rtmp);
- or3(Rtmp, Rdst, Rdst );
-
- bind(aligned);
- if (should_set_CC == set_CC) tst(Rdst);
-}
-
-void InterpreterMacroAssembler::get_cache_index_at_bcp(Register temp, Register index,
- int bcp_offset, size_t index_size) {
- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
- if (index_size == sizeof(u2)) {
- get_2_byte_integer_at_bcp(bcp_offset, temp, index, Unsigned);
- } else if (index_size == sizeof(u4)) {
- get_4_byte_integer_at_bcp(bcp_offset, temp, index);
- assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line");
- xor3(index, -1, index); // convert to plain index
- } else if (index_size == sizeof(u1)) {
- ldub(Lbcp, bcp_offset, index);
- } else {
- ShouldNotReachHere();
- }
-}
-
-
-void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register tmp,
- int bcp_offset, size_t index_size) {
- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
- assert_different_registers(cache, tmp);
- assert_not_delayed();
- get_cache_index_at_bcp(cache, tmp, bcp_offset, index_size);
- // convert from field index to ConstantPoolCacheEntry index and from
- // word index to byte offset
- sll(tmp, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord), tmp);
- add(LcpoolCache, tmp, cache);
-}
-
-
-void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache,
- Register temp,
- Register bytecode,
- int byte_no,
- int bcp_offset,
- size_t index_size) {
- get_cache_and_index_at_bcp(cache, temp, bcp_offset, index_size);
- ld_ptr(cache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset(), bytecode);
- const int shift_count = (1 + byte_no) * BitsPerByte;
- assert((byte_no == TemplateTable::f1_byte && shift_count == ConstantPoolCacheEntry::bytecode_1_shift) ||
- (byte_no == TemplateTable::f2_byte && shift_count == ConstantPoolCacheEntry::bytecode_2_shift),
- "correct shift count");
- srl(bytecode, shift_count, bytecode);
- assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask");
- and3(bytecode, ConstantPoolCacheEntry::bytecode_1_mask, bytecode);
-}
-
-
-void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp,
- int bcp_offset, size_t index_size) {
- assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
- assert_different_registers(cache, tmp);
- assert_not_delayed();
- if (index_size == sizeof(u2)) {
- get_2_byte_integer_at_bcp(bcp_offset, cache, tmp, Unsigned);
- } else {
- ShouldNotReachHere(); // other sizes not supported here
- }
- // convert from field index to ConstantPoolCacheEntry index
- // and from word index to byte offset
- sll(tmp, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord), tmp);
- // skip past the header
- add(tmp, in_bytes(ConstantPoolCache::base_offset()), tmp);
- // construct pointer to cache entry
- add(LcpoolCache, tmp, cache);
-}
-
-
-// Load object from cpool->resolved_references(index)
-void InterpreterMacroAssembler::load_resolved_reference_at_index(
- Register result, Register index, Register tmp) {
- assert_different_registers(result, index, tmp);
- assert_not_delayed();
- // convert from field index to resolved_references() index and from
- // word index to byte offset. Since this is a java object, it can be compressed
- sll(index, LogBytesPerHeapOop, index);
- get_constant_pool(result);
- // load pointer for resolved_references[] objArray
- ld_ptr(result, ConstantPool::cache_offset_in_bytes(), result);
- ld_ptr(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result);
- resolve_oop_handle(result, tmp);
- // Add in the index
- add(result, index, result);
- load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, tmp);
- // The resulting oop is null if the reference is not yet resolved.
- // It is Universe::the_null_sentinel() if the reference resolved to NULL via condy.
-}
-
-
-// load cpool->resolved_klass_at(index)
-void InterpreterMacroAssembler::load_resolved_klass_at_offset(Register Rcpool,
- Register Roffset, Register Rklass) {
- // int value = *this_cp->int_at_addr(which);
- // int resolved_klass_index = extract_low_short_from_int(value);
- //
- // Because SPARC is big-endian, the low_short is at (cpool->int_at_addr(which) + 2 bytes)
- add(Roffset, Rcpool, Roffset);
- lduh(Roffset, sizeof(ConstantPool) + 2, Roffset); // Roffset = resolved_klass_index
-
- Register Rresolved_klasses = Rklass;
- ld_ptr(Rcpool, ConstantPool::resolved_klasses_offset_in_bytes(), Rresolved_klasses);
- sll(Roffset, LogBytesPerWord, Roffset);
- add(Roffset, Array::base_offset_in_bytes(), Roffset);
- ld_ptr(Rresolved_klasses, Roffset, Rklass);
-}
-
-
-// Generate a subtype check: branch to ok_is_subtype if sub_klass is
-// a subtype of super_klass. Blows registers Rsuper_klass, Rsub_klass, tmp1, tmp2.
-void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
- Register Rsuper_klass,
- Register Rtmp1,
- Register Rtmp2,
- Register Rtmp3,
- Label &ok_is_subtype ) {
- Label not_subtype;
-
- // Profile the not-null value's klass.
- profile_typecheck(Rsub_klass, Rtmp1);
-
- check_klass_subtype_fast_path(Rsub_klass, Rsuper_klass,
- Rtmp1, Rtmp2,
- &ok_is_subtype, ¬_subtype, NULL);
-
- check_klass_subtype_slow_path(Rsub_klass, Rsuper_klass,
- Rtmp1, Rtmp2, Rtmp3, /*hack:*/ noreg,
- &ok_is_subtype, NULL);
-
- bind(not_subtype);
- profile_typecheck_failed(Rtmp1);
-}
-
-// Separate these two to allow for delay slot in middle
-// These are used to do a test and full jump to exception-throwing code.
-
-// %%%%% Could possibly reoptimize this by testing to see if could use
-// a single conditional branch (i.e. if span is small enough.
-// If you go that route, than get rid of the split and give up
-// on the delay-slot hack.
-
-void InterpreterMacroAssembler::throw_if_not_1_icc( Condition ok_condition,
- Label& ok ) {
- assert_not_delayed();
- br(ok_condition, true, pt, ok);
- // DELAY SLOT
-}
-
-void InterpreterMacroAssembler::throw_if_not_1_xcc( Condition ok_condition,
- Label& ok ) {
- assert_not_delayed();
- bp( ok_condition, true, Assembler::xcc, pt, ok);
- // DELAY SLOT
-}
-
-void InterpreterMacroAssembler::throw_if_not_1_x( Condition ok_condition,
- Label& ok ) {
- assert_not_delayed();
- brx(ok_condition, true, pt, ok);
- // DELAY SLOT
-}
-
-void InterpreterMacroAssembler::throw_if_not_2( address throw_entry_point,
- Register Rscratch,
- Label& ok ) {
- assert(throw_entry_point != NULL, "entry point must be generated by now");
- AddressLiteral dest(throw_entry_point);
- jump_to(dest, Rscratch);
- delayed()->nop();
- bind(ok);
-}
-
-
-// And if you cannot use the delay slot, here is a shorthand:
-
-void InterpreterMacroAssembler::throw_if_not_icc( Condition ok_condition,
- address throw_entry_point,
- Register Rscratch ) {
- Label ok;
- if (ok_condition != never) {
- throw_if_not_1_icc( ok_condition, ok);
- delayed()->nop();
- }
- throw_if_not_2( throw_entry_point, Rscratch, ok);
-}
-void InterpreterMacroAssembler::throw_if_not_xcc( Condition ok_condition,
- address throw_entry_point,
- Register Rscratch ) {
- Label ok;
- if (ok_condition != never) {
- throw_if_not_1_xcc( ok_condition, ok);
- delayed()->nop();
- }
- throw_if_not_2( throw_entry_point, Rscratch, ok);
-}
-void InterpreterMacroAssembler::throw_if_not_x( Condition ok_condition,
- address throw_entry_point,
- Register Rscratch ) {
- Label ok;
- if (ok_condition != never) {
- throw_if_not_1_x( ok_condition, ok);
- delayed()->nop();
- }
- throw_if_not_2( throw_entry_point, Rscratch, ok);
-}
-
-// Check that index is in range for array, then shift index by index_shift, and put arrayOop + shifted_index into res
-// Note: res is still shy of address by array offset into object.
-
-void InterpreterMacroAssembler::index_check_without_pop(Register array, Register index, int index_shift, Register tmp, Register res) {
- assert_not_delayed();
-
- verify_oop(array);
- // Sign extend since tos (index) can be a 32bit value.
- sra(index, G0, index);
-
- // Check array.
- Label ptr_ok;
- tst(array);
- throw_if_not_1_x(notZero, ptr_ok);
- delayed()->ld(array, arrayOopDesc::length_offset_in_bytes(), tmp); // Check index.
- throw_if_not_2(Interpreter::_throw_NullPointerException_entry, G3_scratch, ptr_ok);
-
- Label index_ok;
- cmp(index, tmp);
- throw_if_not_1_icc(lessUnsigned, index_ok);
- if (index_shift > 0) {
- delayed()->sll(index, index_shift, index);
- } else {
- delayed()->add(array, index, res); // addr - const offset in index
- }
- // Pass the array to create more detailed exceptions.
- // Convention: move aberrant index into Otos_i for exception message.
- mov(index, Otos_i);
- mov(array, G3_scratch);
- throw_if_not_2(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, G4_scratch, index_ok);
-
- // add offset if didn't do it in delay slot
- if (index_shift > 0) { add(array, index, res); } // addr - const offset in index
-}
-
-
-void InterpreterMacroAssembler::index_check(Register array, Register index, int index_shift, Register tmp, Register res) {
- assert_not_delayed();
-
- // pop array
- pop_ptr(array);
-
- // check array
- index_check_without_pop(array, index, index_shift, tmp, res);
-}
-
-
-void InterpreterMacroAssembler::get_const(Register Rdst) {
- ld_ptr(Lmethod, in_bytes(Method::const_offset()), Rdst);
-}
-
-
-void InterpreterMacroAssembler::get_constant_pool(Register Rdst) {
- get_const(Rdst);
- ld_ptr(Rdst, in_bytes(ConstMethod::constants_offset()), Rdst);
-}
-
-
-void InterpreterMacroAssembler::get_constant_pool_cache(Register Rdst) {
- get_constant_pool(Rdst);
- ld_ptr(Rdst, ConstantPool::cache_offset_in_bytes(), Rdst);
-}
-
-
-void InterpreterMacroAssembler::get_cpool_and_tags(Register Rcpool, Register Rtags) {
- get_constant_pool(Rcpool);
- ld_ptr(Rcpool, ConstantPool::tags_offset_in_bytes(), Rtags);
-}
-
-
-// unlock if synchronized method
-//
-// Unlock the receiver if this is a synchronized method.
-// Unlock any Java monitors from syncronized blocks.
-//
-// If there are locked Java monitors
-// If throw_monitor_exception
-// throws IllegalMonitorStateException
-// Else if install_monitor_exception
-// installs IllegalMonitorStateException
-// Else
-// no error processing
-void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state,
- bool throw_monitor_exception,
- bool install_monitor_exception) {
- Label unlocked, unlock, no_unlock;
-
- // get the value of _do_not_unlock_if_synchronized into G1_scratch
- const Address do_not_unlock_if_synchronized(G2_thread,
- JavaThread::do_not_unlock_if_synchronized_offset());
- ldbool(do_not_unlock_if_synchronized, G1_scratch);
- stbool(G0, do_not_unlock_if_synchronized); // reset the flag
-
- // check if synchronized method
- const Address access_flags(Lmethod, Method::access_flags_offset());
- interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
- push(state); // save tos
- ld(access_flags, G3_scratch); // Load access flags.
- btst(JVM_ACC_SYNCHRONIZED, G3_scratch);
- br(zero, false, pt, unlocked);
- delayed()->nop();
-
- // Don't unlock anything if the _do_not_unlock_if_synchronized flag
- // is set.
- cmp_zero_and_br(Assembler::notZero, G1_scratch, no_unlock);
- delayed()->nop();
-
- // BasicObjectLock will be first in list, since this is a synchronized method. However, need
- // to check that the object has not been unlocked by an explicit monitorexit bytecode.
-
- //Intel: if (throw_monitor_exception) ... else ...
- // Entry already unlocked, need to throw exception
- //...
-
- // pass top-most monitor elem
- add( top_most_monitor(), O1 );
-
- ld_ptr(O1, BasicObjectLock::obj_offset_in_bytes(), G3_scratch);
- br_notnull_short(G3_scratch, pt, unlock);
-
- if (throw_monitor_exception) {
- // Entry already unlocked need to throw an exception
- MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
- should_not_reach_here();
- } else {
- // Monitor already unlocked during a stack unroll.
- // If requested, install an illegal_monitor_state_exception.
- // Continue with stack unrolling.
- if (install_monitor_exception) {
- MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
- }
- ba_short(unlocked);
- }
-
- bind(unlock);
-
- unlock_object(O1);
-
- bind(unlocked);
-
- // I0, I1: Might contain return value
-
- // Check that all monitors are unlocked
- { Label loop, exception, entry, restart;
-
- Register Rmptr = O0;
- Register Rtemp = O1;
- Register Rlimit = Lmonitors;
- const jint delta = frame::interpreter_frame_monitor_size() * wordSize;
- assert( (delta & LongAlignmentMask) == 0,
- "sizeof BasicObjectLock must be even number of doublewords");
-
- #ifdef ASSERT
- add(top_most_monitor(), Rmptr, delta);
- { Label L;
- // ensure that Rmptr starts out above (or at) Rlimit
- cmp_and_brx_short(Rmptr, Rlimit, Assembler::greaterEqualUnsigned, pn, L);
- stop("monitor stack has negative size");
- bind(L);
- }
- #endif
- bind(restart);
- ba(entry);
- delayed()->
- add(top_most_monitor(), Rmptr, delta); // points to current entry, starting with bottom-most entry
-
- // Entry is still locked, need to throw exception
- bind(exception);
- if (throw_monitor_exception) {
- MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
- should_not_reach_here();
- } else {
- // Stack unrolling. Unlock object and if requested, install illegal_monitor_exception.
- // Unlock does not block, so don't have to worry about the frame
- unlock_object(Rmptr);
- if (install_monitor_exception) {
- MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
- }
- ba_short(restart);
- }
-
- bind(loop);
- cmp(Rtemp, G0); // check if current entry is used
- brx(Assembler::notEqual, false, pn, exception);
- delayed()->
- dec(Rmptr, delta); // otherwise advance to next entry
- #ifdef ASSERT
- { Label L;
- // ensure that Rmptr has not somehow stepped below Rlimit
- cmp_and_brx_short(Rmptr, Rlimit, Assembler::greaterEqualUnsigned, pn, L);
- stop("ran off the end of the monitor stack");
- bind(L);
- }
- #endif
- bind(entry);
- cmp(Rmptr, Rlimit); // check if bottom reached
- brx(Assembler::notEqual, true, pn, loop); // if not at bottom then check this entry
- delayed()->
- ld_ptr(Rmptr, BasicObjectLock::obj_offset_in_bytes() - delta, Rtemp);
- }
-
- bind(no_unlock);
- pop(state);
- interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
-}
-
-void InterpreterMacroAssembler::narrow(Register result) {
-
- ld_ptr(Address(Lmethod, Method::const_offset()), G3_scratch);
- ldub(G3_scratch, in_bytes(ConstMethod::result_type_offset()), G3_scratch);
-
- Label notBool, notByte, notChar, done;
-
- // common case first
- cmp(G3_scratch, T_INT);
- br(Assembler::equal, true, pn, done);
- delayed()->nop();
-
- cmp(G3_scratch, T_BOOLEAN);
- br(Assembler::notEqual, true, pn, notBool);
- delayed()->cmp(G3_scratch, T_BYTE);
- and3(result, 1, result);
- ba(done);
- delayed()->nop();
-
- bind(notBool);
- // cmp(G3_scratch, T_BYTE);
- br(Assembler::notEqual, true, pn, notByte);
- delayed()->cmp(G3_scratch, T_CHAR);
- sll(result, 24, result);
- sra(result, 24, result);
- ba(done);
- delayed()->nop();
-
- bind(notByte);
- // cmp(G3_scratch, T_CHAR);
- sll(result, 16, result);
- br(Assembler::notEqual, true, pn, done);
- delayed()->sra(result, 16, result);
- // sll(result, 16, result);
- srl(result, 16, result);
-
- // bind(notChar);
- // must be short, instructions already executed in delay slot
- // sll(result, 16, result);
- // sra(result, 16, result);
-
- bind(done);
-}
-
-// remove activation
-//
-// Unlock the receiver if this is a synchronized method.
-// Unlock any Java monitors from syncronized blocks.
-// Remove the activation from the stack.
-//
-// If there are locked Java monitors
-// If throw_monitor_exception
-// throws IllegalMonitorStateException
-// Else if install_monitor_exception
-// installs IllegalMonitorStateException
-// Else
-// no error processing
-void InterpreterMacroAssembler::remove_activation(TosState state,
- bool throw_monitor_exception,
- bool install_monitor_exception) {
-
- unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception);
-
- // save result (push state before jvmti call and pop it afterwards) and notify jvmti
- notify_method_exit(false, state, NotifyJVMTI);
-
- if (StackReservedPages > 0) {
- // testing if Stack Reserved Area needs to be re-enabled
- Label no_reserved_zone_enabling;
- ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G3_scratch);
- cmp_and_brx_short(SP, G3_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling);
-
- call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread);
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError), G2_thread);
- should_not_reach_here();
-
- bind(no_reserved_zone_enabling);
- }
-
- interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
- verify_thread();
-
- // return tos
- assert(Otos_l1 == Otos_i, "adjust code below");
- switch (state) {
- case ltos: mov(Otos_l, Otos_l->after_save()); break; // O0 -> I0
- case btos: // fall through
- case ztos: // fall through
- case ctos:
- case stos: // fall through
- case atos: // fall through
- case itos: mov(Otos_l1, Otos_l1->after_save()); break; // O0 -> I0
- case ftos: // fall through
- case dtos: // fall through
- case vtos: /* nothing to do */ break;
- default : ShouldNotReachHere();
- }
-}
-
-// Lock object
-//
-// Argument - lock_reg points to the BasicObjectLock to be used for locking,
-// it must be initialized with the object to lock
-void InterpreterMacroAssembler::lock_object(Register lock_reg, Register Object) {
- if (UseHeavyMonitors) {
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), lock_reg);
- }
- else {
- Register obj_reg = Object;
- Register mark_reg = G4_scratch;
- Register temp_reg = G1_scratch;
- Address lock_addr(lock_reg, BasicObjectLock::lock_offset_in_bytes());
- Address mark_addr(obj_reg, oopDesc::mark_offset_in_bytes());
- Label done;
-
- Label slow_case;
-
- assert_different_registers(lock_reg, obj_reg, mark_reg, temp_reg);
-
- // load markWord from object into mark_reg
- ld_ptr(mark_addr, mark_reg);
-
- if (UseBiasedLocking) {
- biased_locking_enter(obj_reg, mark_reg, temp_reg, done, &slow_case);
- }
-
- // get the address of basicLock on stack that will be stored in the object
- // we need a temporary register here as we do not want to clobber lock_reg
- // (cas clobbers the destination register)
- mov(lock_reg, temp_reg);
- // set mark reg to be (markWord of object | UNLOCK_VALUE)
- or3(mark_reg, markWord::unlocked_value, mark_reg);
- // initialize the box (Must happen before we update the object mark!)
- st_ptr(mark_reg, lock_addr, BasicLock::displaced_header_offset_in_bytes());
- // compare and exchange object_addr, markWord | 1, stack address of basicLock
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- cas_ptr(mark_addr.base(), mark_reg, temp_reg);
-
- // if the compare and exchange succeeded we are done (we saw an unlocked object)
- cmp_and_brx_short(mark_reg, temp_reg, Assembler::equal, Assembler::pt, done);
-
- // We did not see an unlocked object so try the fast recursive case
-
- // Check if owner is self by comparing the value in the markWord of object
- // with the stack pointer
- sub(temp_reg, SP, temp_reg);
- sub(temp_reg, STACK_BIAS, temp_reg);
- assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
-
- // Composite "andcc" test:
- // (a) %sp -vs- markword proximity check, and,
- // (b) verify mark word LSBs == 0 (Stack-locked).
- //
- // FFFFF003/FFFFFFFFFFFF003 is (markWord::lock_mask_in_place | -os::vm_page_size())
- // Note that the page size used for %sp proximity testing is arbitrary and is
- // unrelated to the actual MMU page size. We use a 'logical' page size of
- // 4096 bytes. F..FFF003 is designed to fit conveniently in the SIMM13 immediate
- // field of the andcc instruction.
- andcc (temp_reg, 0xFFFFF003, G0) ;
-
- // if condition is true we are done and hence we can store 0 in the displaced
- // header indicating it is a recursive lock and be done
- brx(Assembler::zero, true, Assembler::pt, done);
- delayed()->st_ptr(G0, lock_addr, BasicLock::displaced_header_offset_in_bytes());
-
- // none of the above fast optimizations worked so we have to get into the
- // slow case of monitor enter
- bind(slow_case);
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), lock_reg);
-
- bind(done);
- }
-}
-
-// Unlocks an object. Used in monitorexit bytecode and remove_activation.
-//
-// Argument - lock_reg points to the BasicObjectLock for lock
-// Throw IllegalMonitorException if object is not locked by current thread
-void InterpreterMacroAssembler::unlock_object(Register lock_reg) {
- if (UseHeavyMonitors) {
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg);
- } else {
- Register obj_reg = G3_scratch;
- Register mark_reg = G4_scratch;
- Register displaced_header_reg = G1_scratch;
- Address lockobj_addr(lock_reg, BasicObjectLock::obj_offset_in_bytes());
- Address mark_addr(obj_reg, oopDesc::mark_offset_in_bytes());
- Label done;
-
- if (UseBiasedLocking) {
- // load the object out of the BasicObjectLock
- ld_ptr(lockobj_addr, obj_reg);
- biased_locking_exit(mark_addr, mark_reg, done, true);
- st_ptr(G0, lockobj_addr); // free entry
- }
-
- // Test first if we are in the fast recursive case
- Address lock_addr(lock_reg, BasicObjectLock::lock_offset_in_bytes() + BasicLock::displaced_header_offset_in_bytes());
- ld_ptr(lock_addr, displaced_header_reg);
- br_null(displaced_header_reg, true, Assembler::pn, done);
- delayed()->st_ptr(G0, lockobj_addr); // free entry
-
- // See if it is still a light weight lock, if so we just unlock
- // the object and we are done
-
- if (!UseBiasedLocking) {
- // load the object out of the BasicObjectLock
- ld_ptr(lockobj_addr, obj_reg);
- }
-
- // we have the displaced header in displaced_header_reg
- // we expect to see the stack address of the basicLock in case the
- // lock is still a light weight lock (lock_reg)
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- cas_ptr(mark_addr.base(), lock_reg, displaced_header_reg);
- cmp(lock_reg, displaced_header_reg);
- brx(Assembler::equal, true, Assembler::pn, done);
- delayed()->st_ptr(G0, lockobj_addr); // free entry
-
- // The lock has been converted into a heavy lock and hence
- // we need to get into the slow case
-
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg);
-
- bind(done);
- }
-}
-
-// Get the method data pointer from the Method* and set the
-// specified register to its value.
-
-void InterpreterMacroAssembler::set_method_data_pointer() {
- assert(ProfileInterpreter, "must be profiling interpreter");
- Label get_continue;
-
- ld_ptr(Lmethod, in_bytes(Method::method_data_offset()), ImethodDataPtr);
- test_method_data_pointer(get_continue);
- add(ImethodDataPtr, in_bytes(MethodData::data_offset()), ImethodDataPtr);
- bind(get_continue);
-}
-
-// Set the method data pointer for the current bcp.
-
-void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() {
- assert(ProfileInterpreter, "must be profiling interpreter");
- Label zero_continue;
-
- // Test MDO to avoid the call if it is NULL.
- ld_ptr(Lmethod, in_bytes(Method::method_data_offset()), ImethodDataPtr);
- test_method_data_pointer(zero_continue);
- call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), Lmethod, Lbcp);
- add(ImethodDataPtr, in_bytes(MethodData::data_offset()), ImethodDataPtr);
- add(ImethodDataPtr, O0, ImethodDataPtr);
- bind(zero_continue);
-}
-
-// Test ImethodDataPtr. If it is null, continue at the specified label
-
-void InterpreterMacroAssembler::test_method_data_pointer(Label& zero_continue) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- br_null_short(ImethodDataPtr, Assembler::pn, zero_continue);
-}
-
-void InterpreterMacroAssembler::verify_method_data_pointer() {
- assert(ProfileInterpreter, "must be profiling interpreter");
-#ifdef ASSERT
- Label verify_continue;
- test_method_data_pointer(verify_continue);
-
- // If the mdp is valid, it will point to a DataLayout header which is
- // consistent with the bcp. The converse is highly probable also.
- lduh(ImethodDataPtr, in_bytes(DataLayout::bci_offset()), G3_scratch);
- ld_ptr(Lmethod, Method::const_offset(), O5);
- add(G3_scratch, in_bytes(ConstMethod::codes_offset()), G3_scratch);
- add(G3_scratch, O5, G3_scratch);
- cmp(Lbcp, G3_scratch);
- brx(Assembler::equal, false, Assembler::pt, verify_continue);
-
- Register temp_reg = O5;
- delayed()->mov(ImethodDataPtr, temp_reg);
- // %%% should use call_VM_leaf here?
- //call_VM_leaf(noreg, ..., Lmethod, Lbcp, ImethodDataPtr);
- save_frame_and_mov(sizeof(jdouble) / wordSize, Lmethod, O0, Lbcp, O1);
- Address d_save(FP, -sizeof(jdouble) + STACK_BIAS);
- stf(FloatRegisterImpl::D, Ftos_d, d_save);
- mov(temp_reg->after_save(), O2);
- save_thread(L7_thread_cache);
- call(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), relocInfo::none);
- delayed()->nop();
- restore_thread(L7_thread_cache);
- ldf(FloatRegisterImpl::D, d_save, Ftos_d);
- restore();
- bind(verify_continue);
-#endif // ASSERT
-}
-
-void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count,
- Register method_counters,
- Register Rtmp,
- Label &profile_continue) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- // Control will flow to "profile_continue" if the counter is less than the
- // limit or if we call profile_method()
-
- Label done;
-
- // if no method data exists, and the counter is high enough, make one
- br_notnull_short(ImethodDataPtr, Assembler::pn, done);
-
- // Test to see if we should create a method data oop
- Address profile_limit(method_counters, MethodCounters::interpreter_profile_limit_offset());
- ld(profile_limit, Rtmp);
- cmp(invocation_count, Rtmp);
- // Use long branches because call_VM() code and following code generated by
- // test_backedge_count_for_osr() is large in debug VM.
- br(Assembler::lessUnsigned, false, Assembler::pn, profile_continue);
- delayed()->nop();
-
- // Build it now.
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
- set_method_data_pointer_for_bcp();
- ba(profile_continue);
- delayed()->nop();
- bind(done);
-}
-
-// Store a value at some constant offset from the method data pointer.
-
-void InterpreterMacroAssembler::set_mdp_data_at(int constant, Register value) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- st_ptr(value, ImethodDataPtr, constant);
-}
-
-void InterpreterMacroAssembler::increment_mdp_data_at(Address counter,
- Register bumped_count,
- bool decrement) {
- assert(ProfileInterpreter, "must be profiling interpreter");
-
- // Load the counter.
- ld_ptr(counter, bumped_count);
-
- if (decrement) {
- // Decrement the register. Set condition codes.
- subcc(bumped_count, DataLayout::counter_increment, bumped_count);
-
- // If the decrement causes the counter to overflow, stay negative
- Label L;
- brx(Assembler::negative, true, Assembler::pn, L);
-
- // Store the decremented counter, if it is still negative.
- delayed()->st_ptr(bumped_count, counter);
- bind(L);
- } else {
- // Increment the register. Set carry flag.
- addcc(bumped_count, DataLayout::counter_increment, bumped_count);
-
- // If the increment causes the counter to overflow, pull back by 1.
- assert(DataLayout::counter_increment == 1, "subc works");
- subc(bumped_count, G0, bumped_count);
-
- // Store the incremented counter.
- st_ptr(bumped_count, counter);
- }
-}
-
-// Increment the value at some constant offset from the method data pointer.
-
-void InterpreterMacroAssembler::increment_mdp_data_at(int constant,
- Register bumped_count,
- bool decrement) {
- // Locate the counter at a fixed offset from the mdp:
- Address counter(ImethodDataPtr, constant);
- increment_mdp_data_at(counter, bumped_count, decrement);
-}
-
-// Increment the value at some non-fixed (reg + constant) offset from
-// the method data pointer.
-
-void InterpreterMacroAssembler::increment_mdp_data_at(Register reg,
- int constant,
- Register bumped_count,
- Register scratch2,
- bool decrement) {
- // Add the constant to reg to get the offset.
- add(ImethodDataPtr, reg, scratch2);
- Address counter(scratch2, constant);
- increment_mdp_data_at(counter, bumped_count, decrement);
-}
-
-// Set a flag value at the current method data pointer position.
-// Updates a single byte of the header, to avoid races with other header bits.
-
-void InterpreterMacroAssembler::set_mdp_flag_at(int flag_constant,
- Register scratch) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- // Load the data header
- ldub(ImethodDataPtr, in_bytes(DataLayout::flags_offset()), scratch);
-
- // Set the flag
- or3(scratch, flag_constant, scratch);
-
- // Store the modified header.
- stb(scratch, ImethodDataPtr, in_bytes(DataLayout::flags_offset()));
-}
-
-// Test the location at some offset from the method data pointer.
-// If it is not equal to value, branch to the not_equal_continue Label.
-// Set condition codes to match the nullness of the loaded value.
-
-void InterpreterMacroAssembler::test_mdp_data_at(int offset,
- Register value,
- Label& not_equal_continue,
- Register scratch) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- ld_ptr(ImethodDataPtr, offset, scratch);
- cmp(value, scratch);
- brx(Assembler::notEqual, false, Assembler::pn, not_equal_continue);
- delayed()->tst(scratch);
-}
-
-// Update the method data pointer by the displacement located at some fixed
-// offset from the method data pointer.
-
-void InterpreterMacroAssembler::update_mdp_by_offset(int offset_of_disp,
- Register scratch) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- ld_ptr(ImethodDataPtr, offset_of_disp, scratch);
- add(ImethodDataPtr, scratch, ImethodDataPtr);
-}
-
-// Update the method data pointer by the displacement located at the
-// offset (reg + offset_of_disp).
-
-void InterpreterMacroAssembler::update_mdp_by_offset(Register reg,
- int offset_of_disp,
- Register scratch) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- add(reg, offset_of_disp, scratch);
- ld_ptr(ImethodDataPtr, scratch, scratch);
- add(ImethodDataPtr, scratch, ImethodDataPtr);
-}
-
-// Update the method data pointer by a simple constant displacement.
-
-void InterpreterMacroAssembler::update_mdp_by_constant(int constant) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- add(ImethodDataPtr, constant, ImethodDataPtr);
-}
-
-// Update the method data pointer for a _ret bytecode whose target
-// was not among our cached targets.
-
-void InterpreterMacroAssembler::update_mdp_for_ret(TosState state,
- Register return_bci) {
- assert(ProfileInterpreter, "must be profiling interpreter");
- push(state);
- st_ptr(return_bci, l_tmp); // protect return_bci, in case it is volatile
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), return_bci);
- ld_ptr(l_tmp, return_bci);
- pop(state);
-}
-
-// Count a taken branch in the bytecodes.
-
-void InterpreterMacroAssembler::profile_taken_branch(Register scratch, Register bumped_count) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- // We are taking a branch. Increment the taken count.
- increment_mdp_data_at(in_bytes(JumpData::taken_offset()), bumped_count);
-
- // The method data pointer needs to be updated to reflect the new target.
- update_mdp_by_offset(in_bytes(JumpData::displacement_offset()), scratch);
- bind (profile_continue);
- }
-}
-
-
-// Count a not-taken branch in the bytecodes.
-
-void InterpreterMacroAssembler::profile_not_taken_branch(Register scratch) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- // We are taking a branch. Increment the not taken count.
- increment_mdp_data_at(in_bytes(BranchData::not_taken_offset()), scratch);
-
- // The method data pointer needs to be updated to correspond to the
- // next bytecode.
- update_mdp_by_constant(in_bytes(BranchData::branch_data_size()));
- bind (profile_continue);
- }
-}
-
-
-// Count a non-virtual call in the bytecodes.
-
-void InterpreterMacroAssembler::profile_call(Register scratch) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- // We are making a call. Increment the count.
- increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
-
- // The method data pointer needs to be updated to reflect the new target.
- update_mdp_by_constant(in_bytes(CounterData::counter_data_size()));
- bind (profile_continue);
- }
-}
-
-
-// Count a final call in the bytecodes.
-
-void InterpreterMacroAssembler::profile_final_call(Register scratch) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- // We are making a call. Increment the count.
- increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
-
- // The method data pointer needs to be updated to reflect the new target.
- update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
- bind (profile_continue);
- }
-}
-
-
-// Count a virtual call in the bytecodes.
-
-void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
- Register scratch,
- bool receiver_can_be_null) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
-
- Label skip_receiver_profile;
- if (receiver_can_be_null) {
- Label not_null;
- br_notnull_short(receiver, Assembler::pt, not_null);
- // We are making a call. Increment the count for null receiver.
- increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
- ba_short(skip_receiver_profile);
- bind(not_null);
- }
-
- // Record the receiver type.
- record_klass_in_profile(receiver, scratch, true);
- bind(skip_receiver_profile);
-
- // The method data pointer needs to be updated to reflect the new target.
- update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
- bind(profile_continue);
- }
-}
-
-void InterpreterMacroAssembler::record_klass_in_profile_helper(Register receiver, Register scratch,
- Label& done, bool is_virtual_call) {
- if (TypeProfileWidth == 0) {
- if (is_virtual_call) {
- increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
- }
-#if INCLUDE_JVMCI
- else if (EnableJVMCI) {
- increment_mdp_data_at(in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()), scratch);
- }
-#endif
- } else {
- int non_profiled_offset = -1;
- if (is_virtual_call) {
- non_profiled_offset = in_bytes(CounterData::count_offset());
- }
-#if INCLUDE_JVMCI
- else if (EnableJVMCI) {
- non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset());
- }
-#endif
-
- record_item_in_profile_helper(receiver, scratch, 0, done, TypeProfileWidth,
- &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset);
- }
-}
-
-void InterpreterMacroAssembler::record_item_in_profile_helper(Register item,
- Register scratch, int start_row, Label& done, int total_rows,
- OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
- int non_profiled_offset) {
- int last_row = total_rows - 1;
- assert(start_row <= last_row, "must be work left to do");
- // Test this row for both the item and for null.
- // Take any of three different outcomes:
- // 1. found item => increment count and goto done
- // 2. found null => keep looking for case 1, maybe allocate this cell
- // 3. found something else => keep looking for cases 1 and 2
- // Case 3 is handled by a recursive call.
- for (int row = start_row; row <= last_row; row++) {
- Label next_test;
- bool test_for_null_also = (row == start_row);
-
- // See if the item is item[n].
- int item_offset = in_bytes(item_offset_fn(row));
- test_mdp_data_at(item_offset, item, next_test, scratch);
- // delayed()->tst(scratch);
-
- // The receiver is item[n]. Increment count[n].
- int count_offset = in_bytes(item_count_offset_fn(row));
- increment_mdp_data_at(count_offset, scratch);
- ba_short(done);
- bind(next_test);
-
- if (test_for_null_also) {
- Label found_null;
- // Failed the equality check on item[n]... Test for null.
- if (start_row == last_row) {
- // The only thing left to do is handle the null case.
- if (non_profiled_offset >= 0) {
- brx(Assembler::zero, false, Assembler::pn, found_null);
- delayed()->nop();
- // Item did not match any saved item and there is no empty row for it.
- // Increment total counter to indicate polymorphic case.
- increment_mdp_data_at(non_profiled_offset, scratch);
- ba_short(done);
- bind(found_null);
- } else {
- brx(Assembler::notZero, false, Assembler::pt, done);
- delayed()->nop();
- }
- break;
- }
- // Since null is rare, make it be the branch-taken case.
- brx(Assembler::zero, false, Assembler::pn, found_null);
- delayed()->nop();
-
- // Put all the "Case 3" tests here.
- record_item_in_profile_helper(item, scratch, start_row + 1, done, total_rows,
- item_offset_fn, item_count_offset_fn, non_profiled_offset);
-
- // Found a null. Keep searching for a matching item,
- // but remember that this is an empty (unused) slot.
- bind(found_null);
- }
- }
-
- // In the fall-through case, we found no matching item, but we
- // observed the item[start_row] is NULL.
-
- // Fill in the item field and increment the count.
- int item_offset = in_bytes(item_offset_fn(start_row));
- set_mdp_data_at(item_offset, item);
- int count_offset = in_bytes(item_count_offset_fn(start_row));
- mov(DataLayout::counter_increment, scratch);
- set_mdp_data_at(count_offset, scratch);
- if (start_row > 0) {
- ba_short(done);
- }
-}
-
-void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
- Register scratch, bool is_virtual_call) {
- assert(ProfileInterpreter, "must be profiling");
- Label done;
-
- record_klass_in_profile_helper(receiver, scratch, done, is_virtual_call);
-
- bind (done);
-}
-
-
-// Count a ret in the bytecodes.
-
-void InterpreterMacroAssembler::profile_ret(TosState state,
- Register return_bci,
- Register scratch) {
- if (ProfileInterpreter) {
- Label profile_continue;
- uint row;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- // Update the total ret count.
- increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
-
- for (row = 0; row < RetData::row_limit(); row++) {
- Label next_test;
-
- // See if return_bci is equal to bci[n]:
- test_mdp_data_at(in_bytes(RetData::bci_offset(row)),
- return_bci, next_test, scratch);
-
- // return_bci is equal to bci[n]. Increment the count.
- increment_mdp_data_at(in_bytes(RetData::bci_count_offset(row)), scratch);
-
- // The method data pointer needs to be updated to reflect the new target.
- update_mdp_by_offset(in_bytes(RetData::bci_displacement_offset(row)), scratch);
- ba_short(profile_continue);
- bind(next_test);
- }
-
- update_mdp_for_ret(state, return_bci);
-
- bind (profile_continue);
- }
-}
-
-// Profile an unexpected null in the bytecodes.
-void InterpreterMacroAssembler::profile_null_seen(Register scratch) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- set_mdp_flag_at(BitData::null_seen_byte_constant(), scratch);
-
- // The method data pointer needs to be updated.
- int mdp_delta = in_bytes(BitData::bit_data_size());
- if (TypeProfileCasts) {
- mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size());
- }
- update_mdp_by_constant(mdp_delta);
-
- bind (profile_continue);
- }
-}
-
-void InterpreterMacroAssembler::profile_typecheck(Register klass,
- Register scratch) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- int mdp_delta = in_bytes(BitData::bit_data_size());
- if (TypeProfileCasts) {
- mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size());
-
- // Record the object type.
- record_klass_in_profile(klass, scratch, false);
- }
-
- // The method data pointer needs to be updated.
- update_mdp_by_constant(mdp_delta);
-
- bind (profile_continue);
- }
-}
-
-void InterpreterMacroAssembler::profile_typecheck_failed(Register scratch) {
- if (ProfileInterpreter && TypeProfileCasts) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(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(ReceiverTypeData::receiver_type_data_size());
-
- // *Decrement* the counter. We expect to see zero or small negatives.
- increment_mdp_data_at(count_offset, scratch, true);
-
- bind (profile_continue);
- }
-}
-
-// Count the default case of a switch construct.
-
-void InterpreterMacroAssembler::profile_switch_default(Register scratch) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- // Update the default case count
- increment_mdp_data_at(in_bytes(MultiBranchData::default_count_offset()),
- scratch);
-
- // The method data pointer needs to be updated.
- update_mdp_by_offset(
- in_bytes(MultiBranchData::default_displacement_offset()),
- scratch);
-
- bind (profile_continue);
- }
-}
-
-// Count the index'th case of a switch construct.
-
-void InterpreterMacroAssembler::profile_switch_case(Register index,
- Register scratch,
- Register scratch2,
- Register scratch3) {
- if (ProfileInterpreter) {
- Label profile_continue;
-
- // If no method data exists, go to profile_continue.
- test_method_data_pointer(profile_continue);
-
- // Build the base (index * per_case_size_in_bytes()) + case_array_offset_in_bytes()
- set(in_bytes(MultiBranchData::per_case_size()), scratch);
- smul(index, scratch, scratch);
- add(scratch, in_bytes(MultiBranchData::case_array_offset()), scratch);
-
- // Update the case count
- increment_mdp_data_at(scratch,
- in_bytes(MultiBranchData::relative_count_offset()),
- scratch2,
- scratch3);
-
- // The method data pointer needs to be updated.
- update_mdp_by_offset(scratch,
- in_bytes(MultiBranchData::relative_displacement_offset()),
- scratch2);
-
- bind (profile_continue);
- }
-}
-
-void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr, Register tmp) {
- Label not_null, do_nothing, do_update;
-
- assert_different_registers(obj, mdo_addr.base(), tmp);
-
- verify_oop(obj);
-
- ld_ptr(mdo_addr, tmp);
-
- br_notnull_short(obj, pt, not_null);
- or3(tmp, TypeEntries::null_seen, tmp);
- ba_short(do_update);
-
- bind(not_null);
- load_klass(obj, obj);
-
- xor3(obj, tmp, obj);
- btst(TypeEntries::type_klass_mask, obj);
- // klass seen before, nothing to do. The unknown bit may have been
- // set already but no need to check.
- brx(zero, false, pt, do_nothing);
- delayed()->
-
- btst(TypeEntries::type_unknown, obj);
- // already unknown. Nothing to do anymore.
- brx(notZero, false, pt, do_nothing);
- delayed()->
-
- btst(TypeEntries::type_mask, tmp);
- brx(zero, true, pt, do_update);
- // first time here. Set profile type.
- delayed()->or3(tmp, obj, tmp);
-
- // different than before. Cannot keep accurate profile.
- or3(tmp, TypeEntries::type_unknown, tmp);
-
- bind(do_update);
- // update profile
- st_ptr(tmp, mdo_addr);
-
- bind(do_nothing);
-}
-
-void InterpreterMacroAssembler::profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual) {
- if (!ProfileInterpreter) {
- return;
- }
-
- assert_different_registers(callee, tmp1, tmp2, ImethodDataPtr);
-
- if (MethodData::profile_arguments() || MethodData::profile_return()) {
- Label profile_continue;
-
- test_method_data_pointer(profile_continue);
-
- int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
-
- ldub(ImethodDataPtr, in_bytes(DataLayout::tag_offset()) - off_to_start, tmp1);
- cmp_and_br_short(tmp1, is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag, notEqual, pn, profile_continue);
-
- if (MethodData::profile_arguments()) {
- Label done;
- int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
- add(ImethodDataPtr, off_to_args, ImethodDataPtr);
-
- for (int i = 0; i < TypeProfileArgsLimit; i++) {
- if (i > 0 || MethodData::profile_return()) {
- // If return value type is profiled we may have no argument to profile
- ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, tmp1);
- sub(tmp1, i*TypeStackSlotEntries::per_arg_count(), tmp1);
- cmp_and_br_short(tmp1, TypeStackSlotEntries::per_arg_count(), less, pn, done);
- }
- ld_ptr(Address(callee, Method::const_offset()), tmp1);
- lduh(Address(tmp1, ConstMethod::size_of_parameters_offset()), tmp1);
- // stack offset o (zero based) from the start of the argument
- // list, for n arguments translates into offset n - o - 1 from
- // the end of the argument list. But there's an extra slot at
- // the stop of the stack. So the offset is n - o from Lesp.
- ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args, tmp2);
- sub(tmp1, tmp2, tmp1);
-
- // Can't use MacroAssembler::argument_address() which needs Gargs to be set up
- sll(tmp1, Interpreter::logStackElementSize, tmp1);
- ld_ptr(Lesp, tmp1, tmp1);
-
- Address mdo_arg_addr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args);
- profile_obj_type(tmp1, mdo_arg_addr, tmp2);
-
- int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
- add(ImethodDataPtr, to_add, ImethodDataPtr);
- off_to_args += to_add;
- }
-
- if (MethodData::profile_return()) {
- ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, tmp1);
- sub(tmp1, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count(), tmp1);
- }
-
- bind(done);
-
- if (MethodData::profile_return()) {
- // We're right after the type profile for the last
- // argument. tmp1 is the number of cells left in the
- // CallTypeData/VirtualCallTypeData to reach its end. Non null
- // if there's a return to profile.
- assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
- sll(tmp1, exact_log2(DataLayout::cell_size), tmp1);
- add(ImethodDataPtr, tmp1, ImethodDataPtr);
- }
- } else {
- assert(MethodData::profile_return(), "either profile call args or call ret");
- update_mdp_by_constant(in_bytes(TypeEntriesAtCall::return_only_size()));
- }
-
- // mdp points right after the end of the
- // CallTypeData/VirtualCallTypeData, right after the cells for the
- // return value type if there's one.
-
- bind(profile_continue);
- }
-}
-
-void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, Register tmp2) {
- assert_different_registers(ret, tmp1, tmp2);
- if (ProfileInterpreter && MethodData::profile_return()) {
- Label profile_continue, done;
-
- test_method_data_pointer(profile_continue);
-
- if (MethodData::profile_return_jsr292_only()) {
- assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2");
-
- // If we don't profile all invoke bytecodes we must make sure
- // it's a bytecode we indeed profile. We can't go back to the
- // begining of the ProfileData we intend to update to check its
- // type because we're right after it and we don't known its
- // length.
- Label do_profile;
- ldub(Lbcp, 0, tmp1);
- cmp_and_br_short(tmp1, Bytecodes::_invokedynamic, equal, pn, do_profile);
- cmp(tmp1, Bytecodes::_invokehandle);
- br(equal, false, pn, do_profile);
- delayed()->lduh(Lmethod, Method::intrinsic_id_offset_in_bytes(), tmp1);
- cmp_and_br_short(tmp1, vmIntrinsics::_compiledLambdaForm, notEqual, pt, profile_continue);
-
- bind(do_profile);
- }
-
- Address mdo_ret_addr(ImethodDataPtr, -in_bytes(ReturnTypeEntry::size()));
- mov(ret, tmp1);
- profile_obj_type(tmp1, mdo_ret_addr, tmp2);
-
- bind(profile_continue);
- }
-}
-
-void InterpreterMacroAssembler::profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4) {
- if (ProfileInterpreter && MethodData::profile_parameters()) {
- Label profile_continue, done;
-
- test_method_data_pointer(profile_continue);
-
- // Load the offset of the area within the MDO used for
- // parameters. If it's negative we're not profiling any parameters.
- lduw(ImethodDataPtr, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()), tmp1);
- cmp_and_br_short(tmp1, 0, less, pn, profile_continue);
-
- // Compute a pointer to the area for parameters from the offset
- // and move the pointer to the slot for the last
- // parameters. Collect profiling from last parameter down.
- // mdo start + parameters offset + array length - 1
-
- // Pointer to the parameter area in the MDO
- Register mdp = tmp1;
- add(ImethodDataPtr, tmp1, mdp);
-
- // offset of the current profile entry to update
- Register entry_offset = tmp2;
- // entry_offset = array len in number of cells
- ld_ptr(mdp, ArrayData::array_len_offset(), entry_offset);
-
- int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0));
- assert(off_base % DataLayout::cell_size == 0, "should be a number of cells");
-
- // entry_offset (number of cells) = array len - size of 1 entry + offset of the stack slot field
- sub(entry_offset, TypeStackSlotEntries::per_arg_count() - (off_base / DataLayout::cell_size), entry_offset);
- // entry_offset in bytes
- sll(entry_offset, exact_log2(DataLayout::cell_size), entry_offset);
-
- Label loop;
- bind(loop);
-
- // load offset on the stack from the slot for this parameter
- ld_ptr(mdp, entry_offset, tmp3);
- sll(tmp3,Interpreter::logStackElementSize, tmp3);
- neg(tmp3);
- // read the parameter from the local area
- ld_ptr(Llocals, tmp3, tmp3);
-
- // make entry_offset now point to the type field for this parameter
- int type_base = in_bytes(ParametersTypeData::type_offset(0));
- assert(type_base > off_base, "unexpected");
- add(entry_offset, type_base - off_base, entry_offset);
-
- // profile the parameter
- Address arg_type(mdp, entry_offset);
- profile_obj_type(tmp3, arg_type, tmp4);
-
- // go to next parameter
- sub(entry_offset, TypeStackSlotEntries::per_arg_count() * DataLayout::cell_size + (type_base - off_base), entry_offset);
- cmp_and_br_short(entry_offset, off_base, greaterEqual, pt, loop);
-
- bind(profile_continue);
- }
-}
-
-// add a InterpMonitorElem to stack (see frame_sparc.hpp)
-
-void InterpreterMacroAssembler::add_monitor_to_stack( bool stack_is_empty,
- Register Rtemp,
- Register Rtemp2 ) {
-
- Register Rlimit = Lmonitors;
- const jint delta = frame::interpreter_frame_monitor_size() * wordSize;
- assert( (delta & LongAlignmentMask) == 0,
- "sizeof BasicObjectLock must be even number of doublewords");
-
- sub( SP, delta, SP);
- sub( Lesp, delta, Lesp);
- sub( Lmonitors, delta, Lmonitors);
-
- if (!stack_is_empty) {
-
- // must copy stack contents down
-
- Label start_copying, next;
-
- // untested("monitor stack expansion");
- compute_stack_base(Rtemp);
- ba(start_copying);
- delayed()->cmp(Rtemp, Rlimit); // done? duplicated below
-
- // note: must copy from low memory upwards
- // On entry to loop,
- // Rtemp points to new base of stack, Lesp points to new end of stack (1 past TOS)
- // Loop mutates Rtemp
-
- bind( next);
-
- st_ptr(Rtemp2, Rtemp, 0);
- inc(Rtemp, wordSize);
- cmp(Rtemp, Rlimit); // are we done? (duplicated above)
-
- bind( start_copying );
-
- brx( notEqual, true, pn, next );
- delayed()->ld_ptr( Rtemp, delta, Rtemp2 );
-
- // done copying stack
- }
-}
-
-// Locals
-void InterpreterMacroAssembler::access_local_ptr( Register index, Register dst ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
- ld_ptr(index, 0, dst);
- // Note: index must hold the effective address--the iinc template uses it
-}
-
-// Just like access_local_ptr but the tag is a returnAddress
-void InterpreterMacroAssembler::access_local_returnAddress(Register index,
- Register dst ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
- ld_ptr(index, 0, dst);
-}
-
-void InterpreterMacroAssembler::access_local_int( Register index, Register dst ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
- ld(index, 0, dst);
- // Note: index must hold the effective address--the iinc template uses it
-}
-
-
-void InterpreterMacroAssembler::access_local_long( Register index, Register dst ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
- // First half stored at index n+1 (which grows down from Llocals[n])
- load_unaligned_long(index, Interpreter::local_offset_in_bytes(1), dst);
-}
-
-
-void InterpreterMacroAssembler::access_local_float( Register index, FloatRegister dst ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
- ldf(FloatRegisterImpl::S, index, 0, dst);
-}
-
-
-void InterpreterMacroAssembler::access_local_double( Register index, FloatRegister dst ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
- load_unaligned_double(index, Interpreter::local_offset_in_bytes(1), dst);
-}
-
-
-#ifdef ASSERT
-void InterpreterMacroAssembler::check_for_regarea_stomp(Register Rindex, int offset, Register Rlimit, Register Rscratch, Register Rscratch1) {
- Label L;
-
- assert(Rindex != Rscratch, "Registers cannot be same");
- assert(Rindex != Rscratch1, "Registers cannot be same");
- assert(Rlimit != Rscratch, "Registers cannot be same");
- assert(Rlimit != Rscratch1, "Registers cannot be same");
- assert(Rscratch1 != Rscratch, "Registers cannot be same");
-
- // untested("reg area corruption");
- add(Rindex, offset, Rscratch);
- add(Rlimit, 64 + STACK_BIAS, Rscratch1);
- cmp_and_brx_short(Rscratch, Rscratch1, Assembler::greaterEqualUnsigned, pn, L);
- stop("regsave area is being clobbered");
- bind(L);
-}
-#endif // ASSERT
-
-
-void InterpreterMacroAssembler::store_local_int( Register index, Register src ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
- debug_only(check_for_regarea_stomp(index, 0, FP, G1_scratch, G4_scratch);)
- st(src, index, 0);
-}
-
-void InterpreterMacroAssembler::store_local_ptr( Register index, Register src ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
-#ifdef ASSERT
- check_for_regarea_stomp(index, 0, FP, G1_scratch, G4_scratch);
-#endif
- st_ptr(src, index, 0);
-}
-
-
-
-void InterpreterMacroAssembler::store_local_ptr( int n, Register src ) {
- st_ptr(src, Llocals, Interpreter::local_offset_in_bytes(n));
-}
-
-void InterpreterMacroAssembler::store_local_long( Register index, Register src ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
-#ifdef ASSERT
- check_for_regarea_stomp(index, Interpreter::local_offset_in_bytes(1), FP, G1_scratch, G4_scratch);
-#endif
- store_unaligned_long(src, index, Interpreter::local_offset_in_bytes(1)); // which is n+1
-}
-
-
-void InterpreterMacroAssembler::store_local_float( Register index, FloatRegister src ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
-#ifdef ASSERT
- check_for_regarea_stomp(index, 0, FP, G1_scratch, G4_scratch);
-#endif
- stf(FloatRegisterImpl::S, src, index, 0);
-}
-
-
-void InterpreterMacroAssembler::store_local_double( Register index, FloatRegister src ) {
- assert_not_delayed();
- sll(index, Interpreter::logStackElementSize, index);
- sub(Llocals, index, index);
-#ifdef ASSERT
- check_for_regarea_stomp(index, Interpreter::local_offset_in_bytes(1), FP, G1_scratch, G4_scratch);
-#endif
- store_unaligned_double(src, index, Interpreter::local_offset_in_bytes(1));
-}
-
-
-int InterpreterMacroAssembler::top_most_monitor_byte_offset() {
- const jint delta = frame::interpreter_frame_monitor_size() * wordSize;
- int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words, WordsPerLong);
- return ((-rounded_vm_local_words * wordSize) - delta ) + STACK_BIAS;
-}
-
-
-Address InterpreterMacroAssembler::top_most_monitor() {
- return Address(FP, top_most_monitor_byte_offset());
-}
-
-
-void InterpreterMacroAssembler::compute_stack_base( Register Rdest ) {
- add( Lesp, wordSize, Rdest );
-}
-
-void InterpreterMacroAssembler::get_method_counters(Register method,
- Register Rcounters,
- Label& skip) {
- Label has_counters;
- Address method_counters(method, in_bytes(Method::method_counters_offset()));
- ld_ptr(method_counters, Rcounters);
- br_notnull_short(Rcounters, Assembler::pt, has_counters);
- call_VM(noreg, CAST_FROM_FN_PTR(address,
- InterpreterRuntime::build_method_counters), method);
- ld_ptr(method_counters, Rcounters);
- br_null(Rcounters, false, Assembler::pn, skip); // No MethodCounters, OutOfMemory
- delayed()->nop();
- bind(has_counters);
-}
-
-void InterpreterMacroAssembler::increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ) {
- assert(UseCompiler || LogTouchedMethods, "incrementing must be useful");
- assert_different_registers(Rcounters, Rtmp, Rtmp2);
-
- Address inv_counter(Rcounters, MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
- Address be_counter (Rcounters, MethodCounters::backedge_counter_offset() +
- InvocationCounter::counter_offset());
- int delta = InvocationCounter::count_increment;
-
- // Load each counter in a register
- ld( inv_counter, Rtmp );
- ld( be_counter, Rtmp2 );
-
- assert( is_simm13( delta ), " delta too large.");
-
- // Add the delta to the invocation counter and store the result
- add( Rtmp, delta, Rtmp );
-
- // Mask the backedge counter
- and3( Rtmp2, InvocationCounter::count_mask_value, Rtmp2 );
-
- // Store value
- st( Rtmp, inv_counter);
-
- // Add invocation counter + backedge counter
- add( Rtmp, Rtmp2, Rtmp);
-
- // Note that this macro must leave the backedge_count + invocation_count in Rtmp!
-}
-
-void InterpreterMacroAssembler::increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ) {
- assert(UseCompiler, "incrementing must be useful");
- assert_different_registers(Rcounters, Rtmp, Rtmp2);
-
- Address be_counter (Rcounters, MethodCounters::backedge_counter_offset() +
- InvocationCounter::counter_offset());
- Address inv_counter(Rcounters, MethodCounters::invocation_counter_offset() +
- InvocationCounter::counter_offset());
-
- int delta = InvocationCounter::count_increment;
- // Load each counter in a register
- ld( be_counter, Rtmp );
- ld( inv_counter, Rtmp2 );
-
- // Add the delta to the backedge counter
- add( Rtmp, delta, Rtmp );
-
- // Mask the invocation counter, add to backedge counter
- and3( Rtmp2, InvocationCounter::count_mask_value, Rtmp2 );
-
- // and store the result to memory
- st( Rtmp, be_counter );
-
- // Add backedge + invocation counter
- add( Rtmp, Rtmp2, Rtmp );
-
- // Note that this macro must leave backedge_count + invocation_count in Rtmp!
-}
-
-void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_count,
- Register method_counters,
- Register branch_bcp,
- Register Rtmp ) {
- Label did_not_overflow;
- Label overflow_with_error;
- assert_different_registers(backedge_count, Rtmp, branch_bcp);
- assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr");
-
- Address limit(method_counters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()));
- ld(limit, Rtmp);
- cmp_and_br_short(backedge_count, Rtmp, Assembler::lessUnsigned, Assembler::pt, did_not_overflow);
-
- // When ProfileInterpreter is on, the backedge_count comes from the
- // MethodData*, which value does not get reset on the call to
- // frequency_counter_overflow(). To avoid excessive calls to the overflow
- // routine while the method is being compiled, add a second test to make sure
- // the overflow function is called only once every overflow_frequency.
- if (ProfileInterpreter) {
- const int overflow_frequency = 1024;
- andcc(backedge_count, overflow_frequency-1, Rtmp);
- brx(Assembler::notZero, false, Assembler::pt, did_not_overflow);
- delayed()->nop();
- }
-
- // overflow in loop, pass branch bytecode
- set(6,Rtmp);
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), branch_bcp, Rtmp);
-
- // Was an OSR adapter generated?
- // O0 = osr nmethod
- br_null_short(O0, Assembler::pn, overflow_with_error);
-
- // Has the nmethod been invalidated already?
- ldub(O0, nmethod::state_offset(), O2);
- cmp_and_br_short(O2, nmethod::in_use, Assembler::notEqual, Assembler::pn, overflow_with_error);
-
- // migrate the interpreter frame off of the stack
-
- mov(G2_thread, L7);
- // save nmethod
- mov(O0, L6);
- set_last_Java_frame(SP, noreg);
- call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), L7);
- reset_last_Java_frame();
- mov(L7, G2_thread);
-
- // move OSR nmethod to I1
- mov(L6, I1);
-
- // OSR buffer to I0
- mov(O0, I0);
-
- // remove the interpreter frame
- restore(I5_savedSP, 0, SP);
-
- // Jump to the osr code.
- ld_ptr(O1, nmethod::osr_entry_point_offset(), O2);
- jmp(O2, G0);
- delayed()->nop();
-
- bind(overflow_with_error);
-
- bind(did_not_overflow);
-}
-
-
-
-void InterpreterMacroAssembler::interp_verify_oop(Register reg, TosState state, const char * file, int line) {
- if (state == atos) { MacroAssembler::_verify_oop(reg, "broken oop ", file, line); }
-}
-
-
-// local helper function for the verify_oop_or_return_address macro
-static bool verify_return_address(Method* m, int bci) {
-#ifndef PRODUCT
- address pc = (address)(m->constMethod())
- + in_bytes(ConstMethod::codes_offset()) + bci;
- // assume it is a valid return address if it is inside m and is preceded by a jsr
- if (!m->contains(pc)) return false;
- address jsr_pc;
- jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr);
- if (*jsr_pc == Bytecodes::_jsr && jsr_pc >= m->code_base()) return true;
- jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr_w);
- if (*jsr_pc == Bytecodes::_jsr_w && jsr_pc >= m->code_base()) return true;
-#endif // PRODUCT
- return false;
-}
-
-
-void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Register Rtmp) {
- if (!VerifyOops) return;
- // the VM documentation for the astore[_wide] bytecode allows
- // the TOS to be not only an oop but also a return address
- Label test;
- Label skip;
- // See if it is an address (in the current method):
-
- mov(reg, Rtmp);
- const int log2_bytecode_size_limit = 16;
- srl(Rtmp, log2_bytecode_size_limit, Rtmp);
- br_notnull_short( Rtmp, pt, test );
-
- // %%% should use call_VM_leaf here?
- save_frame_and_mov(0, Lmethod, O0, reg, O1);
- save_thread(L7_thread_cache);
- call(CAST_FROM_FN_PTR(address,verify_return_address), relocInfo::none);
- delayed()->nop();
- restore_thread(L7_thread_cache);
- br_notnull( O0, false, pt, skip );
- delayed()->restore();
-
- // Perform a more elaborate out-of-line call
- // Not an address; verify it:
- bind(test);
- verify_oop(reg);
- bind(skip);
-}
-
-
-// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
-void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
- int increment, Address mask_addr,
- Register scratch1, Register scratch2,
- Condition cond, Label *where) {
- ld(counter_addr, scratch1);
- add(scratch1, increment, scratch1);
- ld(mask_addr, scratch2);
- andcc(scratch1, scratch2, G0);
- br(cond, false, Assembler::pn, *where);
- delayed()->st(scratch1, counter_addr);
-}
-
-// Inline assembly for:
-//
-// if (thread is in interp_only_mode) {
-// InterpreterRuntime::post_method_entry();
-// }
-// if (DTraceMethodProbes) {
-// SharedRuntime::dtrace_method_entry(method, receiver);
-// }
-// if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
-// SharedRuntime::rc_trace_method_entry(method, receiver);
-// }
-
-void InterpreterMacroAssembler::notify_method_entry() {
-
- // Whenever JVMTI puts a thread in interp_only_mode, method
- // entry/exit events are sent for that thread to track stack
- // depth. If it is possible to enter interp_only_mode we add
- // the code to check if the event should be sent.
- if (JvmtiExport::can_post_interpreter_events()) {
- Label L;
- Register temp_reg = O5;
- const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset());
- ld(interp_only, temp_reg);
- cmp_and_br_short(temp_reg, 0, equal, pt, L);
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry));
- bind(L);
- }
-
- {
- Register temp_reg = O5;
- SkipIfEqual skip_if(this, temp_reg, &DTraceMethodProbes, zero);
- call_VM_leaf(noreg,
- CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry),
- G2_thread, Lmethod);
- }
-
- // RedefineClasses() tracing support for obsolete method entry
- if (log_is_enabled(Trace, redefine, class, obsolete)) {
- call_VM_leaf(noreg,
- CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
- G2_thread, Lmethod);
- }
-}
-
-
-// Inline assembly for:
-//
-// if (thread is in interp_only_mode) {
-// // save result
-// InterpreterRuntime::post_method_exit();
-// // restore result
-// }
-// if (DTraceMethodProbes) {
-// SharedRuntime::dtrace_method_exit(thread, method);
-// }
-//
-// Native methods have their result stored in d_tmp and l_tmp
-// Java methods have their result stored in the expression stack
-
-void InterpreterMacroAssembler::notify_method_exit(bool is_native_method,
- TosState state,
- NotifyMethodExitMode mode) {
-
- // Whenever JVMTI puts a thread in interp_only_mode, method
- // entry/exit events are sent for that thread to track stack
- // depth. If it is possible to enter interp_only_mode we add
- // the code to check if the event should be sent.
- if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) {
- Label L;
- Register temp_reg = O5;
- const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset());
- ld(interp_only, temp_reg);
- cmp_and_br_short(temp_reg, 0, equal, pt, L);
-
- // Note: frame::interpreter_frame_result has a dependency on how the
- // method result is saved across the call to post_method_exit. For
- // native methods it assumes the result registers are saved to
- // l_scratch and d_scratch. If this changes then the interpreter_frame_result
- // implementation will need to be updated too.
-
- save_return_value(state, is_native_method);
- call_VM(noreg,
- CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit));
- restore_return_value(state, is_native_method);
- bind(L);
- }
-
- {
- Register temp_reg = O5;
- // Dtrace notification
- SkipIfEqual skip_if(this, temp_reg, &DTraceMethodProbes, zero);
- save_return_value(state, is_native_method);
- call_VM_leaf(
- noreg,
- CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit),
- G2_thread, Lmethod);
- restore_return_value(state, is_native_method);
- }
-}
-
-void InterpreterMacroAssembler::save_return_value(TosState state, bool is_native_call) {
- if (is_native_call) {
- stf(FloatRegisterImpl::D, F0, d_tmp);
- stx(O0, l_tmp);
- } else {
- push(state);
- }
-}
-
-void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_native_call) {
- if (is_native_call) {
- ldf(FloatRegisterImpl::D, d_tmp, F0);
- ldx(l_tmp, O0);
- } else {
- pop(state);
- }
-}
diff --git a/src/hotspot/cpu/sparc/interp_masm_sparc.hpp b/src/hotspot/cpu/sparc/interp_masm_sparc.hpp
deleted file mode 100644
index f5f3f576455..00000000000
--- a/src/hotspot/cpu/sparc/interp_masm_sparc.hpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_INTERP_MASM_SPARC_HPP
-#define CPU_SPARC_INTERP_MASM_SPARC_HPP
-
-#include "asm/macroAssembler.hpp"
-#include "interpreter/invocationCounter.hpp"
-
-// This file specializes the assember with interpreter-specific macros
-
-typedef ByteSize (*OffsetFunction)(uint);
-
-REGISTER_DECLARATION( Register, Otos_i , O0); // tos for ints, etc
-REGISTER_DECLARATION( Register, Otos_l , O0); // for longs
-REGISTER_DECLARATION( Register, Otos_l1, O0); // for 1st part of longs
-REGISTER_DECLARATION( Register, Otos_l2, O1); // for 2nd part of longs
-REGISTER_DECLARATION(FloatRegister, Ftos_f , F0); // for floats
-REGISTER_DECLARATION(FloatRegister, Ftos_d , F0); // for doubles
-REGISTER_DECLARATION(FloatRegister, Ftos_d1, F0); // for 1st part of double
-REGISTER_DECLARATION(FloatRegister, Ftos_d2, F1); // for 2nd part of double
-
-class InterpreterMacroAssembler: public MacroAssembler {
- protected:
- // Interpreter specific version of call_VM_base
- virtual void call_VM_leaf_base(
- Register java_thread,
- address entry_point,
- int number_of_arguments
- );
-
- virtual void call_VM_base(
- Register oop_result,
- Register java_thread,
- Register last_java_sp,
- address entry_point,
- int number_of_arguments,
- bool check_exception=true
- );
-
- // base routine for all dispatches
- void dispatch_base(TosState state, address* table);
-
- public:
- InterpreterMacroAssembler(CodeBuffer* c)
- : MacroAssembler(c) {}
-
- virtual void check_and_handle_popframe(Register scratch_reg);
- virtual void check_and_handle_earlyret(Register scratch_reg);
-
- void jump_to_entry(address entry);
-
- virtual void load_earlyret_value(TosState state);
-
- static const Address l_tmp ;
- static const Address d_tmp ;
-
- // helper routine for frame allocation/deallocation
- // compute the delta by which the caller's SP has to
- // be adjusted to accomodate for the non-argument
- // locals
- void compute_extra_locals_size_in_bytes(Register args_size, Register locals_size, Register delta);
-
- // dispatch routines
- void dispatch_prolog(TosState state, int step = 0);
- void dispatch_epilog(TosState state, int step = 0);
- void dispatch_only(TosState state);
- void dispatch_normal(TosState state);
- void dispatch_next(TosState state, int step = 0, bool generate_poll = false);
- void dispatch_next_noverify_oop(TosState state, int step = 0);
- void dispatch_via (TosState state, address* table);
-
-
- void narrow(Register result);
-
- // Removes the current activation (incl. unlocking of monitors).
- // Additionally this code is used for earlyReturn in which case we
- // want to skip throwing an exception and installing an exception.
- void remove_activation(TosState state,
- bool throw_monitor_exception = true,
- bool install_monitor_exception = true);
-
- protected:
- void dispatch_Lbyte_code(TosState state, address* table, int bcp_incr = 0, bool verify = true, bool generate_poll = false);
-
- public:
- // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls
- void super_call_VM(Register thread_cache,
- Register oop_result,
- Register last_java_sp,
- address entry_point,
- Register arg_1,
- Register arg_2,
- bool check_exception = true);
-
- void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2);
-
- // Generate a subtype check: branch to ok_is_subtype if sub_klass is
- // a subtype of super_klass. Blows registers tmp1, tmp2 and tmp3.
- void gen_subtype_check( Register sub_klass, Register super_klass, Register tmp1, Register tmp2, Register tmp3, Label &ok_is_subtype );
-
- // helpers for tossing exceptions
- void throw_if_not_1_icc( Condition ok_condition, Label& ok );
- void throw_if_not_1_xcc( Condition ok_condition, Label& ok );
- void throw_if_not_1_x ( Condition ok_condition, Label& ok ); // chooses icc or xcc based on _LP64
-
- void throw_if_not_2( address throw_entry_point, Register Rscratch, Label& ok);
-
- void throw_if_not_icc( Condition ok_condition, address throw_entry_point, Register Rscratch );
- void throw_if_not_xcc( Condition ok_condition, address throw_entry_point, Register Rscratch );
- void throw_if_not_x ( Condition ok_condition, address throw_entry_point, Register Rscratch );
-
- // helpers for expression stack
-
- void pop_i( Register r = Otos_i);
- void pop_ptr( Register r = Otos_i, Register scratch = O4);
- void pop_l( Register r = Otos_l1);
- // G4_scratch and Lscratch are used at call sites!!
- void pop_f(FloatRegister f = Ftos_f, Register scratch = G1_scratch);
- void pop_d(FloatRegister f = Ftos_d1, Register scratch = G1_scratch);
-
- void push_i( Register r = Otos_i);
- void push_ptr( Register r = Otos_i);
- void push_l( Register r = Otos_l1);
- void push_f(FloatRegister f = Ftos_f);
- void push_d(FloatRegister f = Ftos_d1);
-
-
- void pop (TosState state); // transition vtos -> state
- void push(TosState state); // transition state -> vtos
- void empty_expression_stack(); // resets both Lesp and SP
-
-#ifdef ASSERT
- void verify_sp(Register Rsp, Register Rtemp);
- void verify_esp(Register Resp); // verify that Lesp points to a word in the temp stack
-#endif // ASSERT
-
- public:
- void if_cmp(Condition cc, bool ptr_compare);
-
- // Load values from bytecode stream:
-
- enum signedOrNot { Signed, Unsigned };
- enum setCCOrNot { set_CC, dont_set_CC };
-
- void get_2_byte_integer_at_bcp( int bcp_offset,
- Register Rtmp,
- Register Rdst,
- signedOrNot is_signed,
- setCCOrNot should_set_CC = dont_set_CC );
-
- void get_4_byte_integer_at_bcp( int bcp_offset,
- Register Rtmp,
- Register Rdst,
- setCCOrNot should_set_CC = dont_set_CC );
-
- // Note: "get_cache_and_index" really means "get the index, use it to get the cache entry, and throw away the index".
- void get_cache_and_index_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
- void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register temp, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2));
- void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
- // Note: This one does not fetch the cache. The first argument is a temp which may be killed.
- void get_cache_index_at_bcp(Register temp, Register index, int bcp_offset, size_t index_size = sizeof(u2));
-
- // load cpool->resolved_references(index);
- void load_resolved_reference_at_index(Register result, Register index, Register tmp);
-
- // load cpool->resolved_klass_at(index)
- void load_resolved_klass_at_offset(Register Rcpool, Register Roffset, Register Rklass);
-
- // common code
-
- void field_offset_at(int n, Register tmp, Register dest, Register base);
- int field_offset_at(Register object, address bcp, int offset);
- void fast_iaaccess(int n, address bcp);
- void fast_iaputfield(address bcp, bool do_store_check );
-
- void index_check(Register array, Register index, int index_shift, Register tmp, Register res);
- void index_check_without_pop(Register array, Register index, int index_shift, Register tmp, Register res);
-
- void get_const(Register Rdst);
- void get_constant_pool(Register Rdst);
- void get_constant_pool_cache(Register Rdst);
- void get_cpool_and_tags(Register Rcpool, Register Rtags);
- void is_a(Label& L);
-
- // Load compiled (i2c) or interpreter entry and call from interpreted
- void call_from_interpreter(Register target, Register scratch, Register Rret);
-
- // --------------------------------------------------
-
- void unlock_if_synchronized_method(TosState state, bool throw_monitor_exception = true, bool install_monitor_exception = true);
-
- void add_monitor_to_stack( bool stack_is_empty,
- Register Rtemp,
- Register Rtemp2 );
-
- // Load/store aligned in _LP64 but unaligned otherwise
- // These only apply to the Interpreter expression stack and locals!
- void load_unaligned_double(Register r1, int offset, FloatRegister d);
- void store_unaligned_double(FloatRegister d, Register r1, int offset );
-
- // Load/store aligned in _LP64 but unaligned otherwise
- void load_unaligned_long(Register r1, int offset, Register d);
- void store_unaligned_long(Register d, Register r1, int offset );
-
- void access_local_int( Register index, Register dst );
- void access_local_ptr( Register index, Register dst );
- void access_local_returnAddress( Register index, Register dst );
- void access_local_long( Register index, Register dst );
- void access_local_float( Register index, FloatRegister dst );
- void access_local_double( Register index, FloatRegister dst );
-#ifdef ASSERT
- void check_for_regarea_stomp( Register Rindex, int offset, Register Rlimit, Register Rscratch, Register Rscratch1);
-#endif // ASSERT
- void store_local_int( Register index, Register src );
- void store_local_ptr( Register index, Register src );
- void store_local_ptr( int n, Register src );
- void store_local_long( Register index, Register src );
- void store_local_float( Register index, FloatRegister src );
- void store_local_double( Register index, FloatRegister src );
-
- // Helpers for swap and dup
- void load_ptr(int n, Register val);
- void store_ptr(int n, Register val);
-
- // Helper for getting receiver in register.
- void load_receiver(Register param_count, Register recv);
-
- static int top_most_monitor_byte_offset(); // offset in bytes to top of monitor block
- Address top_most_monitor();
- void compute_stack_base( Register Rdest );
-
- void get_method_counters(Register method, Register Rcounters, Label& skip);
- void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 );
- void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 );
- void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register branch_bcp, Register Rtmp );
-
- // Object locking
- void lock_object (Register lock_reg, Register obj_reg);
- void unlock_object(Register lock_reg);
-
- // Interpreter profiling operations
- void set_method_data_pointer();
- void set_method_data_pointer_for_bcp();
- void test_method_data_pointer(Label& zero_continue);
- void verify_method_data_pointer();
- void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rtmp, Label &profile_continue);
-
- void set_mdp_data_at(int constant, Register value);
- void increment_mdp_data_at(Address counter, Register bumped_count,
- bool decrement = false);
- void increment_mdp_data_at(int constant, Register bumped_count,
- bool decrement = false);
- void increment_mdp_data_at(Register reg, int constant,
- Register bumped_count, Register scratch2,
- bool decrement = false);
- void increment_mask_and_jump(Address counter_addr,
- int increment, Address mask_addr,
- Register scratch1, Register scratch2,
- Condition cond, Label *where);
- void set_mdp_flag_at(int flag_constant, Register scratch);
- void test_mdp_data_at(int offset, Register value, Label& not_equal_continue,
- Register scratch);
-
- void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call);
- void record_klass_in_profile_helper(Register receiver, Register scratch,
- Label& done, bool is_virtual_call);
- void record_item_in_profile_helper(Register item,
- Register scratch, int start_row, Label& done, int total_rows,
- OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn,
- int non_profiled_offset);
-
- void update_mdp_by_offset(int offset_of_disp, Register scratch);
- void update_mdp_by_offset(Register reg, int offset_of_disp,
- Register scratch);
- void update_mdp_by_constant(int constant);
- void update_mdp_for_ret(TosState state, Register return_bci);
-
- void profile_taken_branch(Register scratch, Register bumped_count);
- void profile_not_taken_branch(Register scratch);
- void profile_call(Register scratch);
- void profile_final_call(Register scratch);
- void profile_virtual_call(Register receiver, Register scratch, bool receiver_can_be_null = false);
- void profile_ret(TosState state, Register return_bci, Register scratch);
- void profile_null_seen(Register scratch);
- void profile_typecheck(Register klass, Register scratch);
- void profile_typecheck_failed(Register scratch);
- void profile_switch_default(Register scratch);
- void profile_switch_case(Register index,
- Register scratch1,
- Register scratch2,
- Register scratch3);
-
- void profile_obj_type(Register obj, const Address& mdo_addr, Register tmp);
- void profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual);
- void profile_return_type(Register ret, Register tmp1, Register tmp2);
- void profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4);
-
- // Debugging
- void interp_verify_oop(Register reg, TosState state, const char * file, int line); // only if +VerifyOops && state == atos
- void verify_oop_or_return_address(Register reg, Register rtmp); // for astore
- void verify_FPU(int stack_depth, TosState state = ftos) {} // No-op.
-
- // support for JVMTI/Dtrace
- typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode;
- void notify_method_entry();
- void notify_method_exit(
- bool save_result, TosState state, NotifyMethodExitMode mode);
-
- void save_return_value(TosState state, bool is_native_call);
- void restore_return_value(TosState state, bool is_native_call);
-
-};
-
-#endif // CPU_SPARC_INTERP_MASM_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp b/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp
deleted file mode 100644
index 9f6ba143094..00000000000
--- a/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "interpreter/interp_masm.hpp"
-#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "memory/allocation.inline.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/icache.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/signature.hpp"
-
-
-#define __ _masm->
-
-
-// Implementation of SignatureHandlerGenerator
-InterpreterRuntime::SignatureHandlerGenerator::SignatureHandlerGenerator(
- const methodHandle& method, CodeBuffer* buffer) : NativeSignatureIterator(method) {
- _masm = new MacroAssembler(buffer);
-}
-
-void InterpreterRuntime::SignatureHandlerGenerator::pass_word(int size_of_arg, int offset_in_arg) {
- Argument jni_arg(jni_offset() + offset_in_arg, false);
- Register Rtmp = O0;
- __ ld(Llocals, Interpreter::local_offset_in_bytes(offset()), Rtmp);
-
- __ store_argument(Rtmp, jni_arg);
-}
-
-void InterpreterRuntime::SignatureHandlerGenerator::pass_long() {
- Argument jni_arg(jni_offset(), false);
- Register Rtmp = O0;
-
- __ ldx(Llocals, Interpreter::local_offset_in_bytes(offset() + 1), Rtmp);
- __ store_long_argument(Rtmp, jni_arg);
-}
-
-
-void InterpreterRuntime::SignatureHandlerGenerator::pass_float() {
- Argument jni_arg(jni_offset(), false);
- FloatRegister Rtmp = F0;
- __ ldf(FloatRegisterImpl::S, Llocals, Interpreter::local_offset_in_bytes(offset()), Rtmp);
- __ store_float_argument(Rtmp, jni_arg);
-}
-
-
-void InterpreterRuntime::SignatureHandlerGenerator::pass_double() {
- Argument jni_arg(jni_offset(), false);
- FloatRegister Rtmp = F0;
- __ ldf(FloatRegisterImpl::D, Llocals, Interpreter::local_offset_in_bytes(offset() + 1), Rtmp);
- __ store_double_argument(Rtmp, jni_arg);
-}
-
-void InterpreterRuntime::SignatureHandlerGenerator::pass_object() {
- Argument jni_arg(jni_offset(), false);
- Argument java_arg( offset(), true);
- Register Rtmp1 = O0;
- Register Rtmp2 = jni_arg.is_register() ? jni_arg.as_register() : O0;
- Register Rtmp3 = G3_scratch;
-
- // the handle for a receiver will never be null
- bool do_NULL_check = offset() != 0 || is_static();
-
- Address h_arg = Address(Llocals, Interpreter::local_offset_in_bytes(offset()));
- __ ld_ptr(h_arg, Rtmp1);
- if (!do_NULL_check) {
- __ add(h_arg.base(), h_arg.disp(), Rtmp2);
- } else {
- if (Rtmp1 == Rtmp2)
- __ tst(Rtmp1);
- else __ addcc(G0, Rtmp1, Rtmp2); // optimize mov/test pair
- Label L;
- __ brx(Assembler::notZero, true, Assembler::pt, L);
- __ delayed()->add(h_arg.base(), h_arg.disp(), Rtmp2);
- __ bind(L);
- }
- __ store_ptr_argument(Rtmp2, jni_arg); // this is often a no-op
-}
-
-
-void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) {
-
- // generate code to handle arguments
- iterate(fingerprint);
-
- // return result handler
- AddressLiteral result_handler(Interpreter::result_handler(method()->result_type()));
- __ sethi(result_handler, Lscratch);
- __ retl();
- __ delayed()->add(Lscratch, result_handler.low10(), Lscratch);
-
- __ flush();
-}
-
-
-// Implementation of SignatureHandlerLibrary
-
-void SignatureHandlerLibrary::pd_set_handler(address handler) {}
-
-
-class SlowSignatureHandler: public NativeSignatureIterator {
- private:
- address _from;
- intptr_t* _to;
- intptr_t* _RegArgSignature; // Signature of first Arguments to be passed in Registers
- uint _argcount;
-
- enum { // We need to differenciate float from non floats in reg args
- non_float = 0,
- float_sig = 1,
- double_sig = 2,
- long_sig = 3
- };
-
- virtual void pass_int() {
- *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
- _from -= Interpreter::stackElementSize;
- add_signature( non_float );
- }
-
- virtual void pass_object() {
- // pass address of from
- intptr_t *from_addr = (intptr_t*)(_from + Interpreter::local_offset_in_bytes(0));
- *_to++ = (*from_addr == 0) ? NULL : (intptr_t) from_addr;
- _from -= Interpreter::stackElementSize;
- add_signature( non_float );
- }
-
- virtual void pass_float() {
- *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
- _from -= Interpreter::stackElementSize;
- add_signature( float_sig );
- }
-
- virtual void pass_double() {
- *_to++ = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
- _from -= 2*Interpreter::stackElementSize;
- add_signature( double_sig );
- }
-
- virtual void pass_long() {
- _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
- _to += 1;
- _from -= 2*Interpreter::stackElementSize;
- add_signature( long_sig );
- }
-
- virtual void add_signature( intptr_t sig_type ) {
- if ( _argcount < (sizeof (intptr_t))*4 ) {
- *_RegArgSignature |= (sig_type << (_argcount*2) );
- _argcount++;
- }
- }
-
-
- public:
- SlowSignatureHandler(const methodHandle& method, address from, intptr_t* to, intptr_t *RegArgSig) : NativeSignatureIterator(method) {
- _from = from;
- _to = to;
- _RegArgSignature = RegArgSig;
- *_RegArgSignature = 0;
- _argcount = method->is_static() ? 2 : 1;
- }
-};
-
-
-JRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(
- JavaThread* thread,
- Method* method,
- intptr_t* from,
- intptr_t* to ))
- methodHandle m(thread, method);
- assert(m->is_native(), "sanity check");
- // handle arguments
- // Warning: We use reg arg slot 00 temporarily to return the RegArgSignature
- // back to the code that pops the arguments into the CPU registers
- SlowSignatureHandler(m, (address)from, m->is_static() ? to+2 : to+1, to).iterate((uint64_t)CONST64(-1));
- // return result handler
- return Interpreter::result_handler(m->result_type());
-JRT_END
diff --git a/src/hotspot/cpu/sparc/interpreterRT_sparc.hpp b/src/hotspot/cpu/sparc/interpreterRT_sparc.hpp
deleted file mode 100644
index 11f3c2e9c74..00000000000
--- a/src/hotspot/cpu/sparc/interpreterRT_sparc.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_INTERPRETERRT_SPARC_HPP
-#define CPU_SPARC_INTERPRETERRT_SPARC_HPP
-
-// This is included in the middle of class Interpreter.
-// Do not include files here.
-
-
-static int binary_search(int key, LookupswitchPair* array, int n);
-
-static address iload (JavaThread* thread);
-static address aload (JavaThread* thread);
-static address istore(JavaThread* thread);
-static address astore(JavaThread* thread);
-static address iinc (JavaThread* thread);
-
-
-
-// native method calls
-
-class SignatureHandlerGenerator: public NativeSignatureIterator {
- private:
- MacroAssembler* _masm;
-
- void pass_word(int size_of_arg, int offset_in_arg);
- void pass_int() { pass_word(1, 0); }
- void pass_long();
- void pass_double();
- void pass_float();
- void pass_object();
-
- public:
- // Creation
- SignatureHandlerGenerator(const methodHandle& method, CodeBuffer* buffer);
-
- // Code generation
- void generate( uint64_t fingerprint );
-};
-
-#endif // CPU_SPARC_INTERPRETERRT_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/javaFrameAnchor_sparc.hpp b/src/hotspot/cpu/sparc/javaFrameAnchor_sparc.hpp
deleted file mode 100644
index dadf4a1481c..00000000000
--- a/src/hotspot/cpu/sparc/javaFrameAnchor_sparc.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_JAVAFRAMEANCHOR_SPARC_HPP
-#define CPU_SPARC_JAVAFRAMEANCHOR_SPARC_HPP
-
-private:
- volatile int _flags;
-
-public:
-
- enum pd_Constants {
- flushed = 1 // winodows have flushed
- };
-
- int flags(void) { return _flags; }
- void set_flags(int flags) { _flags = flags; }
-
- static ByteSize flags_offset() { return byte_offset_of(JavaFrameAnchor, _flags); }
-
- // Each arch must define clear, copy
- // These are used by objects that only care about:
- // 1 - initializing a new state (thread creation, javaCalls)
- // 2 - saving a current state (javaCalls)
- // 3 - restoring an old state (javaCalls)
-
- void clear(void) {
- // clearing _last_Java_sp must be first
- _last_Java_sp = NULL;
- // fence?
- _flags = 0;
- _last_Java_pc = NULL;
- }
-
- void copy(JavaFrameAnchor* src) {
- // In order to make sure the transition state is valid for "this"
- // We must clear _last_Java_sp before copying the rest of the new data
- //
- // Hack Alert: Temporary bugfix for 4717480/4721647
- // To act like previous version (pd_cache_state) don't NULL _last_Java_sp
- // unless the value is changing
- //
- if (_last_Java_sp != src->_last_Java_sp)
- _last_Java_sp = NULL;
-
- _flags = src->_flags;
- _last_Java_pc = src->_last_Java_pc;
- // Must be last so profiler will always see valid frame if has_last_frame() is true
- _last_Java_sp = src->_last_Java_sp;
- }
-
- // Is stack walkable
- inline bool walkable( void) {
- return _flags & flushed;
- }
-
- void make_walkable(JavaThread* thread);
-
- void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; }
-
- address last_Java_pc(void) { return _last_Java_pc; }
-
- // These are only used by friends
-private:
-
- intptr_t* last_Java_sp() const {
- // _last_Java_sp will always be a an unbiased stack pointer
- // if is is biased then some setter screwed up. This is
- // deadly.
- assert(((intptr_t)_last_Java_sp & 0xF) == 0, "Biased last_Java_sp");
- return _last_Java_sp;
- }
-
- void capture_last_Java_pc(intptr_t* sp);
-
- void set_window_flushed( void) {
- _flags |= flushed;
- OrderAccess::fence();
- }
-
-#endif // CPU_SPARC_JAVAFRAMEANCHOR_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp b/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp
deleted file mode 100644
index 82947a0fe48..00000000000
--- a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/barrierSet.hpp"
-#include "gc/shared/barrierSetAssembler.hpp"
-#include "memory/resourceArea.hpp"
-#include "prims/jniFastGetField.hpp"
-#include "prims/jvm_misc.hpp"
-#include "runtime/safepoint.hpp"
-
-// TSO ensures that loads are blocking and ordered with respect to
-// to earlier loads, so we don't need LoadLoad membars.
-
-#define __ masm->
-
-#define BUFFER_SIZE 30*sizeof(jint)
-
-// Common register usage:
-// O0: env
-// O1: obj
-// O2: jfieldID
-// O4: offset (O2 >> 2)
-// G4: old safepoint counter
-
-address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
- const char *name;
- switch (type) {
- case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break;
- case T_BYTE: name = "jni_fast_GetByteField"; break;
- case T_CHAR: name = "jni_fast_GetCharField"; break;
- case T_SHORT: name = "jni_fast_GetShortField"; break;
- case T_INT: name = "jni_fast_GetIntField"; break;
- default: ShouldNotReachHere();
- }
- ResourceMark rm;
- BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize);
- CodeBuffer cbuf(blob);
- MacroAssembler* masm = new MacroAssembler(&cbuf);
- address fast_entry = __ pc();
-
- Label label1, label2;
-
- AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr());
- __ sethi (cnt_addrlit, O3);
- Address cnt_addr(O3, cnt_addrlit.low10());
- __ ld (cnt_addr, G4);
- __ andcc (G4, 1, G0);
- __ br (Assembler::notZero, false, Assembler::pn, label1);
- __ delayed()->srl (O2, 2, O4);
-
- if (JvmtiExport::can_post_field_access()) {
- // Check to see if a field access watch has been set before we
- // take the fast path.
- AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr());
- __ load_contents(get_field_access_count_addr, O5);
- __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pn, label1);
- }
-
- __ mov(O1, O5);
-
- // Both O5 and G3 are clobbered by try_resolve_jobject_in_native.
- BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->try_resolve_jobject_in_native(masm, /* jni_env */ O0, /* obj */ O5, /* tmp */ G3, label1);
-
- assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
- speculative_load_pclist[count] = __ pc();
- switch (type) {
- case T_BOOLEAN: __ ldub (O5, O4, G3); break;
- case T_BYTE: __ ldsb (O5, O4, G3); break;
- case T_CHAR: __ lduh (O5, O4, G3); break;
- case T_SHORT: __ ldsh (O5, O4, G3); break;
- case T_INT: __ ld (O5, O4, G3); break;
- default: ShouldNotReachHere();
- }
-
- __ ld (cnt_addr, O5);
- __ cmp (O5, G4);
- __ br (Assembler::notEqual, false, Assembler::pn, label2);
- __ delayed()->mov (O7, G1);
- __ retl ();
- __ delayed()->mov (G3, O0);
-
- slowcase_entry_pclist[count++] = __ pc();
- __ bind (label1);
- __ mov (O7, G1);
-
- address slow_case_addr;
- switch (type) {
- case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break;
- case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break;
- case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break;
- case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break;
- case T_INT: slow_case_addr = jni_GetIntField_addr(); break;
- default: ShouldNotReachHere();
- }
- __ bind (label2);
- __ call (slow_case_addr, relocInfo::none);
- __ delayed()->mov (G1, O7);
-
- __ flush ();
-
- return fast_entry;
-}
-
-address JNI_FastGetField::generate_fast_get_boolean_field() {
- return generate_fast_get_int_field0(T_BOOLEAN);
-}
-
-address JNI_FastGetField::generate_fast_get_byte_field() {
- return generate_fast_get_int_field0(T_BYTE);
-}
-
-address JNI_FastGetField::generate_fast_get_char_field() {
- return generate_fast_get_int_field0(T_CHAR);
-}
-
-address JNI_FastGetField::generate_fast_get_short_field() {
- return generate_fast_get_int_field0(T_SHORT);
-}
-
-address JNI_FastGetField::generate_fast_get_int_field() {
- return generate_fast_get_int_field0(T_INT);
-}
-
-address JNI_FastGetField::generate_fast_get_long_field() {
- const char *name = "jni_fast_GetLongField";
- ResourceMark rm;
- BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize);
- CodeBuffer cbuf(blob);
- MacroAssembler* masm = new MacroAssembler(&cbuf);
- address fast_entry = __ pc();
-
- Label label1, label2;
-
- AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr());
- __ sethi (cnt_addrlit, G3);
- Address cnt_addr(G3, cnt_addrlit.low10());
- __ ld (cnt_addr, G4);
- __ andcc (G4, 1, G0);
- __ br (Assembler::notZero, false, Assembler::pn, label1);
- __ delayed()->srl (O2, 2, O4);
-
- if (JvmtiExport::can_post_field_access()) {
- // Check to see if a field access watch has been set before we
- // take the fast path.
- AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr());
- __ load_contents(get_field_access_count_addr, O5);
- __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pn, label1);
- }
-
- __ mov(O1, O5);
-
- // Both O5 and G1 are clobbered by try_resolve_jobject_in_native.
- BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->try_resolve_jobject_in_native(masm, /* jni_env */ O0, /* obj */ O5, /* tmp */ G1, label1);
- DEBUG_ONLY(__ set(0xDEADC0DE, G1);)
-
- __ add (O5, O4, O5);
-
- assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
- speculative_load_pclist[count] = __ pc();
- __ ldx (O5, 0, O3);
-
- __ ld (cnt_addr, G1);
- __ cmp (G1, G4);
- __ br (Assembler::notEqual, false, Assembler::pn, label2);
- __ delayed()->mov (O7, G1);
-
- __ retl ();
- __ delayed()->mov (O3, O0);
-
- slowcase_entry_pclist[count++] = __ pc();
-
- __ bind (label1);
- __ mov (O7, G1);
-
- address slow_case_addr = jni_GetLongField_addr();
- __ bind (label2);
- __ call (slow_case_addr, relocInfo::none);
- __ delayed()->mov (G1, O7);
-
- __ flush ();
-
- return fast_entry;
-}
-
-address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
- const char *name;
- switch (type) {
- case T_FLOAT: name = "jni_fast_GetFloatField"; break;
- case T_DOUBLE: name = "jni_fast_GetDoubleField"; break;
- default: ShouldNotReachHere();
- }
- ResourceMark rm;
- BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize);
- CodeBuffer cbuf(blob);
- MacroAssembler* masm = new MacroAssembler(&cbuf);
- address fast_entry = __ pc();
-
- Label label1, label2;
-
- AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr());
- __ sethi (cnt_addrlit, O3);
- Address cnt_addr(O3, cnt_addrlit.low10());
- __ ld (cnt_addr, G4);
- __ andcc (G4, 1, G0);
- __ br (Assembler::notZero, false, Assembler::pn, label1);
- __ delayed()->srl (O2, 2, O4);
-
- if (JvmtiExport::can_post_field_access()) {
- // Check to see if a field access watch has been set before we
- // take the fast path.
- AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr());
- __ load_contents(get_field_access_count_addr, O5);
- __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pn, label1);
- }
-
- __ mov(O1, O5);
-
- // Both O5 and G3 are clobbered by try_resolve_jobject_in_native.
- BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->try_resolve_jobject_in_native(masm, /* jni_env */ O0, /* obj */ O5, /* tmp */ G3, label1);
- DEBUG_ONLY(__ set(0xDEADC0DE, G3);)
-
- assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
- speculative_load_pclist[count] = __ pc();
- switch (type) {
- case T_FLOAT: __ ldf (FloatRegisterImpl::S, O5, O4, F0); break;
- case T_DOUBLE: __ ldf (FloatRegisterImpl::D, O5, O4, F0); break;
- default: ShouldNotReachHere();
- }
-
- __ ld (cnt_addr, O5);
- __ cmp (O5, G4);
- __ br (Assembler::notEqual, false, Assembler::pn, label2);
- __ delayed()->mov (O7, G1);
-
- __ retl ();
- __ delayed()-> nop ();
-
- slowcase_entry_pclist[count++] = __ pc();
- __ bind (label1);
- __ mov (O7, G1);
-
- address slow_case_addr;
- switch (type) {
- case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break;
- case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break;
- default: ShouldNotReachHere();
- }
- __ bind (label2);
- __ call (slow_case_addr, relocInfo::none);
- __ delayed()->mov (G1, O7);
-
- __ flush ();
-
- return fast_entry;
-}
-
-address JNI_FastGetField::generate_fast_get_float_field() {
- return generate_fast_get_float_field0(T_FLOAT);
-}
-
-address JNI_FastGetField::generate_fast_get_double_field() {
- return generate_fast_get_float_field0(T_DOUBLE);
-}
diff --git a/src/hotspot/cpu/sparc/jniTypes_sparc.hpp b/src/hotspot/cpu/sparc/jniTypes_sparc.hpp
deleted file mode 100644
index 75ecf48ec64..00000000000
--- a/src/hotspot/cpu/sparc/jniTypes_sparc.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_JNITYPES_SPARC_HPP
-#define CPU_SPARC_JNITYPES_SPARC_HPP
-
-#include "jni.h"
-#include "memory/allocation.hpp"
-#include "oops/oop.hpp"
-
-// This file holds platform-dependent routines used to write primitive jni
-// types to the array of arguments passed into JavaCalls::call
-
-class JNITypes : AllStatic {
- // These functions write a java primitive type (in native format)
- // to a java stack slot array to be passed as an argument to JavaCalls:calls.
- // I.e., they are functionally 'push' operations if they have a 'pos'
- // formal parameter. Note that jlong's and jdouble's are written
- // _in reverse_ of the order in which they appear in the interpreter
- // stack. This is because call stubs (see stubGenerator_sparc.cpp)
- // reverse the argument list constructed by JavaCallArguments (see
- // javaCalls.hpp).
-
-private:
- // Helper routines.
- static inline void put_int2 (jint *from, jint *to) { to[0] = from[0]; to[1] = from[1]; }
- static inline void put_int2 (jint *from, jint *to, int& pos) { put_int2 (from, (jint *)((intptr_t *)to + pos)); pos += 2; }
- static inline void put_int2r(jint *from, jint *to) { to[0] = from[1]; to[1] = from[0]; }
- static inline void put_int2r(jint *from, jint *to, int& pos) { put_int2r(from, (jint *)((intptr_t *)to + pos)); pos += 2; }
-
-public:
- // Ints are stored in native format in one JavaCallArgument slot at *to.
- static inline void put_int(jint from, intptr_t *to) { *(jint *)(to + 0 ) = from; }
- static inline void put_int(jint from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = from; }
- static inline void put_int(jint *from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = *from; }
-
- // Longs are stored in native format in one JavaCallArgument slot at *(to+1).
- static inline void put_long(jlong from, intptr_t *to) { *(jlong *)(to + 1 + 0) = from; }
- static inline void put_long(jlong from, intptr_t *to, int& pos) { *(jlong *)(to + 1 + pos) = from; pos += 2; }
- static inline void put_long(jlong *from, intptr_t *to, int& pos) { *(jlong *)(to + 1 + pos) = *from; pos += 2; }
-
- // Oops are stored in native format in one JavaCallArgument slot at *to.
- static inline void put_obj(oop from, intptr_t *to) { *(oop *)(to + 0 ) = from; }
- static inline void put_obj(oop from, intptr_t *to, int& pos) { *(oop *)(to + pos++) = from; }
- static inline void put_obj(oop *from, intptr_t *to, int& pos) { *(oop *)(to + pos++) = *from; }
-
- // Floats are stored in native format in one JavaCallArgument slot at *to.
- static inline void put_float(jfloat from, intptr_t *to) { *(jfloat *)(to + 0 ) = from; }
- static inline void put_float(jfloat from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = from; }
- static inline void put_float(jfloat *from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = *from; }
-
- // Doubles are stored in native word format in one JavaCallArgument slot at *(to+1).
- static inline void put_double(jdouble from, intptr_t *to) { *(jdouble *)(to + 1 + 0) = from; }
- static inline void put_double(jdouble from, intptr_t *to, int& pos) { *(jdouble *)(to + 1 + pos) = from; pos += 2; }
- static inline void put_double(jdouble *from, intptr_t *to, int& pos) { *(jdouble *)(to + 1 + pos) = *from; pos += 2; }
-
- // The get_xxx routines, on the other hand, actually _do_ fetch
- // java primitive types from the interpreter stack.
- static inline jint get_int(intptr_t *from) { return *(jint *)from; }
-
- static inline jlong get_long(intptr_t *from) { return *(jlong *)from; }
-
- static inline oop get_obj(intptr_t *from) { return *(oop *)from; }
- static inline jfloat get_float(intptr_t *from) { return *(jfloat *)from; }
-
- static inline jdouble get_double(intptr_t *from) { return *(jdouble *)from; }
-
-};
-
-#endif // CPU_SPARC_JNITYPES_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp b/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp
deleted file mode 100644
index f8fdf782a0e..00000000000
--- a/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "jvmci/jvmciCodeInstaller.hpp"
-#include "jvmci/jvmciRuntime.hpp"
-#include "jvmci/jvmciCompilerToVM.hpp"
-#include "jvmci/jvmciJavaClasses.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "utilities/align.hpp"
-#include "vmreg_sparc.inline.hpp"
-
-jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMCIObject method, JVMCI_TRAPS) {
- if (inst->is_call() || inst->is_jump()) {
- return pc_offset + NativeCall::instruction_size;
- } else if (inst->is_call_reg()) {
- return pc_offset + NativeCallReg::instruction_size;
- } else if (inst->is_sethi()) {
- return pc_offset + NativeFarCall::instruction_size;
- } else {
- JVMCI_ERROR_0("unsupported type of instruction for call site");
- return 0;
- }
-}
-
-void CodeInstaller::pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) {
- address pc = _instructions->start() + pc_offset;
- Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK);
- jobject value = JNIHandles::make_local(obj());
- if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) {
- int oop_index = _oop_recorder->find_index(value);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
- _instructions->relocate(pc, rspec, 1);
- } else {
- NativeMovConstReg* move = nativeMovConstReg_at(pc);
- move->set_data((intptr_t) value);
-
- // We need two relocations: one on the sethi and one on the add.
- int oop_index = _oop_recorder->find_index(value);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
- _instructions->relocate(pc + NativeMovConstReg::sethi_offset, rspec);
- _instructions->relocate(pc + NativeMovConstReg::add_offset, rspec);
- }
-}
-
-void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) {
- address pc = _instructions->start() + pc_offset;
- if (jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant)) {
- NativeMovConstReg32* move = nativeMovConstReg32_at(pc);
- narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, JVMCI_CHECK);
- move->set_data((intptr_t)narrowOop);
- TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop);
- } else {
- NativeMovConstReg* move = nativeMovConstReg_at(pc);
- void* reference = record_metadata_reference(_instructions, pc, constant, JVMCI_CHECK);
- move->set_data((intptr_t)reference);
- TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference));
- }
-}
-
-void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, JVMCI_TRAPS) {
- address pc = _instructions->start() + pc_offset;
- NativeInstruction* inst = nativeInstruction_at(pc);
- NativeInstruction* inst1 = nativeInstruction_at(pc + 4);
- if(inst->is_sethi() && inst1->is_nop()) {
- address const_start = _constants->start();
- address dest = _constants->start() + data_offset;
- if(_constants_size > 0) {
- _instructions->relocate(pc + NativeMovConstReg::sethi_offset, internal_word_Relocation::spec((address) dest));
- _instructions->relocate(pc + NativeMovConstReg::add_offset, internal_word_Relocation::spec((address) dest));
- }
- TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset);
- }else {
- int const_size = align_up(_constants->end()-_constants->start(), CodeEntryAlignment);
- NativeMovRegMem* load = nativeMovRegMem_at(pc);
- // This offset must match with SPARCLoadConstantTableBaseOp.emitCode
- load->set_offset(- (const_size - data_offset + Assembler::min_simm13()));
- TRACE_jvmci_3("relocating ld at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset);
- }
-}
-
-void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, JVMCI_TRAPS) {
- address pc = (address) inst;
- if (inst->is_call()) {
- NativeCall* call = nativeCall_at(pc);
- call->set_destination((address) foreign_call_destination);
- _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());
- } else if (inst->is_sethi()) {
- NativeJump* jump = nativeJump_at(pc);
- jump->set_jump_destination((address) foreign_call_destination);
- _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
- } else {
- JVMCI_ERROR("unknown call or jump instruction at " PTR_FORMAT, p2i(pc));
- }
- TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
-}
-
-void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, JVMCIObject hotspot_method, jint pc_offset, JVMCI_TRAPS) {
-#ifdef ASSERT
- Method* method = NULL;
- // we need to check, this might also be an unresolved method
- if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(hotspot_method)) {
- method = JVMCIENV->asMethod(hotspot_method);
- }
-#endif
- switch (_next_call_type) {
- case INLINE_INVOKE:
- break;
- case INVOKEVIRTUAL:
- case INVOKEINTERFACE: {
- assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface");
- NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
- call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
- _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc));
- break;
- }
- case INVOKESTATIC: {
- assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic");
- NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
- call->set_destination(SharedRuntime::get_resolve_static_call_stub());
- _instructions->relocate(call->instruction_address(), relocInfo::static_call_type);
- break;
- }
- case INVOKESPECIAL: {
- assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial");
- NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
- call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
- _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type);
- break;
- }
- default:
- JVMCI_ERROR("invalid _next_call_type value");
- break;
- }
-}
-
-void CodeInstaller::pd_relocate_poll(address pc, jint mark, JVMCI_TRAPS) {
- switch (mark) {
- case POLL_NEAR:
- JVMCI_ERROR("unimplemented");
- break;
- case POLL_FAR:
- _instructions->relocate(pc, relocInfo::poll_type);
- break;
- case POLL_RETURN_NEAR:
- JVMCI_ERROR("unimplemented");
- break;
- case POLL_RETURN_FAR:
- _instructions->relocate(pc, relocInfo::poll_return_type);
- break;
- default:
- JVMCI_ERROR("invalid mark value");
- break;
- }
-}
-
-// convert JVMCI register indices (as used in oop maps) to HotSpot registers
-VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, JVMCI_TRAPS) {
- // JVMCI Registers are numbered as follows:
- // 0..31: Thirty-two General Purpose registers (CPU Registers)
- // 32..63: Thirty-two single precision float registers
- // 64..95: Thirty-two double precision float registers
- // 96..111: Sixteen quad precision float registers
- if (jvmci_reg < 32) {
- return as_Register(jvmci_reg)->as_VMReg();
- } else {
- jint floatRegisterNumber;
- if(jvmci_reg < 64) { // Single precision
- floatRegisterNumber = jvmci_reg - 32;
- } else if(jvmci_reg < 96) {
- floatRegisterNumber = 2 * (jvmci_reg - 64);
- } else if(jvmci_reg < 112) {
- floatRegisterNumber = 4 * (jvmci_reg - 96);
- } else {
- JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg);
- }
- return as_FloatRegister(floatRegisterNumber)->as_VMReg();
- }
-}
-
-bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
- return !hotspotRegister->is_FloatRegister();
-}
diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp
deleted file mode 100644
index 8ebb634686a..00000000000
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp
+++ /dev/null
@@ -1,3950 +0,0 @@
-/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "jvm.h"
-#include "asm/macroAssembler.inline.hpp"
-#include "compiler/disassembler.hpp"
-#include "gc/shared/collectedHeap.inline.hpp"
-#include "gc/shared/barrierSet.hpp"
-#include "gc/shared/barrierSetAssembler.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/resourceArea.hpp"
-#include "memory/universe.hpp"
-#include "oops/accessDecorators.hpp"
-#include "oops/compressedOops.hpp"
-#include "oops/klass.inline.hpp"
-#include "prims/methodHandles.hpp"
-#include "runtime/biasedLocking.hpp"
-#include "runtime/flags/flagSetting.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/jniHandles.inline.hpp"
-#include "runtime/objectMonitor.hpp"
-#include "runtime/os.inline.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/safepointMechanism.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "utilities/align.hpp"
-#include "utilities/macros.hpp"
-#include "utilities/powerOfTwo.hpp"
-
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) /* nothing */
-#define STOP(error) stop(error)
-#else
-#define BLOCK_COMMENT(str) block_comment(str)
-#define STOP(error) block_comment(error); stop(error)
-#endif
-
-// Convert the raw encoding form into the form expected by the
-// constructor for Address.
-Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) {
- assert(scale == 0, "not supported");
- RelocationHolder rspec;
- if (disp_reloc != relocInfo::none) {
- rspec = Relocation::spec_simple(disp_reloc);
- }
-
- Register rindex = as_Register(index);
- if (rindex != G0) {
- Address madr(as_Register(base), rindex);
- madr._rspec = rspec;
- return madr;
- } else {
- Address madr(as_Register(base), disp);
- madr._rspec = rspec;
- return madr;
- }
-}
-
-Address Argument::address_in_frame() const {
- // Warning: In LP64 mode disp will occupy more than 10 bits, but
- // op codes such as ld or ldx, only access disp() to get
- // their simm13 argument.
- int disp = ((_number - Argument::n_register_parameters + frame::memory_parameter_word_sp_offset) * BytesPerWord) + STACK_BIAS;
- if (is_in())
- return Address(FP, disp); // In argument.
- else
- return Address(SP, disp); // Out argument.
-}
-
-static const char* argumentNames[][2] = {
- {"A0","P0"}, {"A1","P1"}, {"A2","P2"}, {"A3","P3"}, {"A4","P4"},
- {"A5","P5"}, {"A6","P6"}, {"A7","P7"}, {"A8","P8"}, {"A9","P9"},
- {"A(n>9)","P(n>9)"}
-};
-
-const char* Argument::name() const {
- int nofArgs = sizeof argumentNames / sizeof argumentNames[0];
- int num = number();
- if (num >= nofArgs) num = nofArgs - 1;
- return argumentNames[num][is_in() ? 1 : 0];
-}
-
-#ifdef ASSERT
-// On RISC, there's no benefit to verifying instruction boundaries.
-bool AbstractAssembler::pd_check_instruction_mark() { return false; }
-#endif
-
-// Patch instruction inst at offset inst_pos to refer to dest_pos
-// and return the resulting instruction.
-// We should have pcs, not offsets, but since all is relative, it will work out
-// OK.
-int MacroAssembler::patched_branch(int dest_pos, int inst, int inst_pos) {
- int m; // mask for displacement field
- int v; // new value for displacement field
- const int word_aligned_ones = -4;
- switch (inv_op(inst)) {
- default: ShouldNotReachHere();
- case call_op: m = wdisp(word_aligned_ones, 0, 30); v = wdisp(dest_pos, inst_pos, 30); break;
- case branch_op:
- switch (inv_op2(inst)) {
- case fbp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break;
- case bp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break;
- case fb_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
- case br_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
- case bpr_op2: {
- if (is_cbcond(inst)) {
- m = wdisp10(word_aligned_ones, 0);
- v = wdisp10(dest_pos, inst_pos);
- } else {
- m = wdisp16(word_aligned_ones, 0);
- v = wdisp16(dest_pos, inst_pos);
- }
- break;
- }
- default: ShouldNotReachHere();
- }
- }
- return inst & ~m | v;
-}
-
-// Return the offset of the branch destionation of instruction inst
-// at offset pos.
-// Should have pcs, but since all is relative, it works out.
-int MacroAssembler::branch_destination(int inst, int pos) {
- int r;
- switch (inv_op(inst)) {
- default: ShouldNotReachHere();
- case call_op: r = inv_wdisp(inst, pos, 30); break;
- case branch_op:
- switch (inv_op2(inst)) {
- case fbp_op2: r = inv_wdisp( inst, pos, 19); break;
- case bp_op2: r = inv_wdisp( inst, pos, 19); break;
- case fb_op2: r = inv_wdisp( inst, pos, 22); break;
- case br_op2: r = inv_wdisp( inst, pos, 22); break;
- case bpr_op2: {
- if (is_cbcond(inst)) {
- r = inv_wdisp10(inst, pos);
- } else {
- r = inv_wdisp16(inst, pos);
- }
- break;
- }
- default: ShouldNotReachHere();
- }
- }
- return r;
-}
-
-void MacroAssembler::resolve_jobject(Register value, Register tmp) {
- Label done, not_weak;
- br_null(value, false, Assembler::pn, done); // Use NULL as-is.
- delayed()->andcc(value, JNIHandles::weak_tag_mask, G0); // Test for jweak
- brx(Assembler::zero, true, Assembler::pt, not_weak);
- delayed()->nop();
- access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
- Address(value, -JNIHandles::weak_tag_value), value, tmp);
- verify_oop(value);
- br (Assembler::always, true, Assembler::pt, done);
- delayed()->nop();
- bind(not_weak);
- access_load_at(T_OBJECT, IN_NATIVE, Address(value, 0), value, tmp);
- verify_oop(value);
- bind(done);
-}
-
-void MacroAssembler::null_check(Register reg, int offset) {
- if (needs_explicit_null_check((intptr_t)offset)) {
- // provoke OS NULL exception if reg = NULL by
- // accessing M[reg] w/o changing any registers
- ld_ptr(reg, 0, G0);
- }
- else {
- // nothing to do, (later) access of M[reg + offset]
- // will provoke OS NULL exception if reg = NULL
- }
-}
-
-// Ring buffer jumps
-
-
-void MacroAssembler::jmp2(Register r1, Register r2, const char* file, int line ) {
- assert_not_delayed();
- jmpl(r1, r2, G0);
-}
-void MacroAssembler::jmp(Register r1, int offset, const char* file, int line ) {
- assert_not_delayed();
- jmp(r1, offset);
-}
-
-// This code sequence is relocatable to any address, even on LP64.
-void MacroAssembler::jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line) {
- assert_not_delayed();
- // Force fixed length sethi because NativeJump and NativeFarCall don't handle
- // variable length instruction streams.
- patchable_sethi(addrlit, temp);
- Address a(temp, addrlit.low10() + offset); // Add the offset to the displacement.
- jmpl(a.base(), a.disp(), d);
-}
-
-void MacroAssembler::jump(const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line) {
- jumpl(addrlit, temp, G0, offset, file, line);
-}
-
-
-// Conditional breakpoint (for assertion checks in assembly code)
-void MacroAssembler::breakpoint_trap(Condition c, CC cc) {
- trap(c, cc, G0, ST_RESERVED_FOR_USER_0);
-}
-
-// We want to use ST_BREAKPOINT here, but the debugger is confused by it.
-void MacroAssembler::breakpoint_trap() {
- trap(ST_RESERVED_FOR_USER_0);
-}
-
-void MacroAssembler::safepoint_poll(Label& slow_path, bool a, Register thread_reg, Register temp_reg) {
- ldx(Address(thread_reg, Thread::polling_page_offset()), temp_reg, 0);
- // Armed page has poll bit set.
- and3(temp_reg, SafepointMechanism::poll_bit(), temp_reg);
- br_notnull(temp_reg, a, Assembler::pn, slow_path);
-}
-
-void MacroAssembler::enter() {
- Unimplemented();
-}
-
-void MacroAssembler::leave() {
- Unimplemented();
-}
-
-// Calls to C land
-
-#ifdef ASSERT
-// a hook for debugging
-static Thread* reinitialize_thread() {
- return Thread::current();
-}
-#else
-#define reinitialize_thread Thread::current
-#endif
-
-#ifdef ASSERT
-address last_get_thread = NULL;
-#endif
-
-// call this when G2_thread is not known to be valid
-void MacroAssembler::get_thread() {
- save_frame(0); // to avoid clobbering O0
- mov(G1, L0); // avoid clobbering G1
- mov(G5_method, L1); // avoid clobbering G5
- mov(G3, L2); // avoid clobbering G3 also
- mov(G4, L5); // avoid clobbering G4
-#ifdef ASSERT
- AddressLiteral last_get_thread_addrlit(&last_get_thread);
- set(last_get_thread_addrlit, L3);
- rdpc(L4);
- inc(L4, 3 * BytesPerInstWord); // skip rdpc + inc + st_ptr to point L4 at call st_ptr(L4, L3, 0);
-#endif
- call(CAST_FROM_FN_PTR(address, reinitialize_thread), relocInfo::runtime_call_type);
- delayed()->nop();
- mov(L0, G1);
- mov(L1, G5_method);
- mov(L2, G3);
- mov(L5, G4);
- restore(O0, 0, G2_thread);
-}
-
-static Thread* verify_thread_subroutine(Thread* gthread_value) {
- Thread* correct_value = Thread::current();
- guarantee(gthread_value == correct_value, "G2_thread value must be the thread");
- return correct_value;
-}
-
-void MacroAssembler::verify_thread() {
- if (VerifyThread) {
- // NOTE: this chops off the heads of the 64-bit O registers.
- // make sure G2_thread contains the right value
- save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod)
- mov(G1, L1); // avoid clobbering G1
- // G2 saved below
- mov(G3, L3); // avoid clobbering G3
- mov(G4, L4); // avoid clobbering G4
- mov(G5_method, L5); // avoid clobbering G5_method
- call(CAST_FROM_FN_PTR(address,verify_thread_subroutine), relocInfo::runtime_call_type);
- delayed()->mov(G2_thread, O0);
-
- mov(L1, G1); // Restore G1
- // G2 restored below
- mov(L3, G3); // restore G3
- mov(L4, G4); // restore G4
- mov(L5, G5_method); // restore G5_method
- restore(O0, 0, G2_thread);
- }
-}
-
-
-void MacroAssembler::save_thread(const Register thread_cache) {
- verify_thread();
- if (thread_cache->is_valid()) {
- assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile");
- mov(G2_thread, thread_cache);
- }
- if (VerifyThread) {
- // smash G2_thread, as if the VM were about to anyway
- set(0x67676767, G2_thread);
- }
-}
-
-
-void MacroAssembler::restore_thread(const Register thread_cache) {
- if (thread_cache->is_valid()) {
- assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile");
- mov(thread_cache, G2_thread);
- verify_thread();
- } else {
- // do it the slow way
- get_thread();
- }
-}
-
-
-// %%% maybe get rid of [re]set_last_Java_frame
-void MacroAssembler::set_last_Java_frame(Register last_java_sp, Register last_Java_pc) {
- assert_not_delayed();
- Address flags(G2_thread, JavaThread::frame_anchor_offset() +
- JavaFrameAnchor::flags_offset());
- Address pc_addr(G2_thread, JavaThread::last_Java_pc_offset());
-
- // Always set last_Java_pc and flags first because once last_Java_sp is visible
- // has_last_Java_frame is true and users will look at the rest of the fields.
- // (Note: flags should always be zero before we get here so doesn't need to be set.)
-
-#ifdef ASSERT
- // Verify that flags was zeroed on return to Java
- Label PcOk;
- save_frame(0); // to avoid clobbering O0
- ld_ptr(pc_addr, L0);
- br_null_short(L0, Assembler::pt, PcOk);
- STOP("last_Java_pc not zeroed before leaving Java");
- bind(PcOk);
-
- // Verify that flags was zeroed on return to Java
- Label FlagsOk;
- ld(flags, L0);
- tst(L0);
- br(Assembler::zero, false, Assembler::pt, FlagsOk);
- delayed() -> restore();
- STOP("flags not zeroed before leaving Java");
- bind(FlagsOk);
-#endif /* ASSERT */
- //
- // When returning from calling out from Java mode the frame anchor's last_Java_pc
- // will always be set to NULL. It is set here so that if we are doing a call to
- // native (not VM) that we capture the known pc and don't have to rely on the
- // native call having a standard frame linkage where we can find the pc.
-
- if (last_Java_pc->is_valid()) {
- st_ptr(last_Java_pc, pc_addr);
- }
-
-#ifdef ASSERT
- // Make sure that we have an odd stack
- Label StackOk;
- andcc(last_java_sp, 0x01, G0);
- br(Assembler::notZero, false, Assembler::pt, StackOk);
- delayed()->nop();
- STOP("Stack Not Biased in set_last_Java_frame");
- bind(StackOk);
-#endif // ASSERT
- assert( last_java_sp != G4_scratch, "bad register usage in set_last_Java_frame");
- add( last_java_sp, STACK_BIAS, G4_scratch );
- st_ptr(G4_scratch, G2_thread, JavaThread::last_Java_sp_offset());
-}
-
-void MacroAssembler::reset_last_Java_frame(void) {
- assert_not_delayed();
-
- Address sp_addr(G2_thread, JavaThread::last_Java_sp_offset());
- Address pc_addr(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset());
- Address flags (G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset());
-
-#ifdef ASSERT
- // check that it WAS previously set
- save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame
- ld_ptr(sp_addr, L0);
- tst(L0);
- breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
- restore();
-#endif // ASSERT
-
- st_ptr(G0, sp_addr);
- // Always return last_Java_pc to zero
- st_ptr(G0, pc_addr);
- // Always null flags after return to Java
- st(G0, flags);
-}
-
-
-void MacroAssembler::call_VM_base(
- Register oop_result,
- Register thread_cache,
- Register last_java_sp,
- address entry_point,
- int number_of_arguments,
- bool check_exceptions)
-{
- assert_not_delayed();
-
- // determine last_java_sp register
- if (!last_java_sp->is_valid()) {
- last_java_sp = SP;
- }
- // debugging support
- assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
-
- // 64-bit last_java_sp is biased!
- set_last_Java_frame(last_java_sp, noreg);
- if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early
- save_thread(thread_cache);
- // do the call
- call(entry_point, relocInfo::runtime_call_type);
- if (!VerifyThread)
- delayed()->mov(G2_thread, O0); // pass thread as first argument
- else
- delayed()->nop(); // (thread already passed)
- restore_thread(thread_cache);
- reset_last_Java_frame();
-
- // check for pending exceptions. use Gtemp as scratch register.
- if (check_exceptions) {
- check_and_forward_exception(Gtemp);
- }
-
-#ifdef ASSERT
- set(badHeapWordVal, G3);
- set(badHeapWordVal, G4);
- set(badHeapWordVal, G5);
-#endif
-
- // get oop result if there is one and reset the value in the thread
- if (oop_result->is_valid()) {
- get_vm_result(oop_result);
- }
-}
-
-void MacroAssembler::check_and_forward_exception(Register scratch_reg)
-{
- Label L;
-
- check_and_handle_popframe(scratch_reg);
- check_and_handle_earlyret(scratch_reg);
-
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- ld_ptr(exception_addr, scratch_reg);
- br_null_short(scratch_reg, pt, L);
- // we use O7 linkage so that forward_exception_entry has the issuing PC
- call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type);
- delayed()->nop();
- bind(L);
-}
-
-
-void MacroAssembler::check_and_handle_popframe(Register scratch_reg) {
-}
-
-
-void MacroAssembler::check_and_handle_earlyret(Register scratch_reg) {
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
- call_VM_base(oop_result, noreg, noreg, entry_point, number_of_arguments, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- call_VM(oop_result, entry_point, 1, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- call_VM(oop_result, entry_point, 2, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument");
- call_VM(oop_result, entry_point, 3, check_exceptions);
-}
-
-
-
-// Note: The following call_VM overloadings are useful when a "save"
-// has already been performed by a stub, and the last Java frame is
-// the previous one. In that case, last_java_sp must be passed as FP
-// instead of SP.
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments, bool check_exceptions) {
- call_VM_base(oop_result, noreg, last_java_sp, entry_point, number_of_arguments, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument");
- call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions);
-}
-
-
-
-void MacroAssembler::call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments) {
- assert_not_delayed();
- save_thread(thread_cache);
- // do the call
- call(entry_point, relocInfo::runtime_call_type);
- delayed()->nop();
- restore_thread(thread_cache);
-#ifdef ASSERT
- set(badHeapWordVal, G3);
- set(badHeapWordVal, G4);
- set(badHeapWordVal, G5);
-#endif
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments) {
- call_VM_leaf_base(thread_cache, entry_point, number_of_arguments);
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1) {
- mov(arg_1, O0);
- call_VM_leaf(thread_cache, entry_point, 1);
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) {
- mov(arg_1, O0);
- mov(arg_2, O1); assert(arg_2 != O0, "smashed argument");
- call_VM_leaf(thread_cache, entry_point, 2);
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3) {
- mov(arg_1, O0);
- mov(arg_2, O1); assert(arg_2 != O0, "smashed argument");
- mov(arg_3, O2); assert(arg_3 != O0 && arg_3 != O1, "smashed argument");
- call_VM_leaf(thread_cache, entry_point, 3);
-}
-
-
-void MacroAssembler::get_vm_result(Register oop_result) {
- verify_thread();
- Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
- ld_ptr( vm_result_addr, oop_result);
- st_ptr(G0, vm_result_addr);
- verify_oop(oop_result);
-}
-
-
-void MacroAssembler::get_vm_result_2(Register metadata_result) {
- verify_thread();
- Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset());
- ld_ptr(vm_result_addr_2, metadata_result);
- st_ptr(G0, vm_result_addr_2);
-}
-
-
-// We require that C code which does not return a value in vm_result will
-// leave it undisturbed.
-void MacroAssembler::set_vm_result(Register oop_result) {
- verify_thread();
- Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
- verify_oop(oop_result);
-
-# ifdef ASSERT
- // Check that we are not overwriting any other oop.
- save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod
- ld_ptr(vm_result_addr, L0);
- tst(L0);
- restore();
- breakpoint_trap(notZero, Assembler::ptr_cc);
- // }
-# endif
-
- st_ptr(oop_result, vm_result_addr);
-}
-
-
-void MacroAssembler::ic_call(address entry, bool emit_delay, jint method_index) {
- RelocationHolder rspec = virtual_call_Relocation::spec(pc(), method_index);
- patchable_set((intptr_t)Universe::non_oop_word(), G5_inline_cache_reg);
- relocate(rspec);
- call(entry, relocInfo::none);
- if (emit_delay) {
- delayed()->nop();
- }
-}
-
-
-void MacroAssembler::internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) {
- address save_pc;
- int shiftcnt;
-#ifdef VALIDATE_PIPELINE
- assert_no_delay("Cannot put two instructions in delay-slot.");
-#endif
- v9_dep();
- save_pc = pc();
-
- int msb32 = (int) (addrlit.value() >> 32);
- int lsb32 = (int) (addrlit.value());
-
- if (msb32 == 0 && lsb32 >= 0) {
- Assembler::sethi(lsb32, d, addrlit.rspec());
- }
- else if (msb32 == -1) {
- Assembler::sethi(~lsb32, d, addrlit.rspec());
- xor3(d, ~low10(~0), d);
- }
- else {
- Assembler::sethi(msb32, d, addrlit.rspec()); // msb 22-bits
- if (msb32 & 0x3ff) // Any bits?
- or3(d, msb32 & 0x3ff, d); // msb 32-bits are now in lsb 32
- if (lsb32 & 0xFFFFFC00) { // done?
- if ((lsb32 >> 20) & 0xfff) { // Any bits set?
- sllx(d, 12, d); // Make room for next 12 bits
- or3(d, (lsb32 >> 20) & 0xfff, d); // Or in next 12
- shiftcnt = 0; // We already shifted
- }
- else
- shiftcnt = 12;
- if ((lsb32 >> 10) & 0x3ff) {
- sllx(d, shiftcnt + 10, d); // Make room for last 10 bits
- or3(d, (lsb32 >> 10) & 0x3ff, d); // Or in next 10
- shiftcnt = 0;
- }
- else
- shiftcnt = 10;
- sllx(d, shiftcnt + 10, d); // Shift leaving disp field 0'd
- }
- else
- sllx(d, 32, d);
- }
- // Pad out the instruction sequence so it can be patched later.
- if (ForceRelocatable || (addrlit.rtype() != relocInfo::none &&
- addrlit.rtype() != relocInfo::runtime_call_type)) {
- while (pc() < (save_pc + (7 * BytesPerInstWord)))
- nop();
- }
-}
-
-
-void MacroAssembler::sethi(const AddressLiteral& addrlit, Register d) {
- internal_sethi(addrlit, d, false);
-}
-
-
-void MacroAssembler::patchable_sethi(const AddressLiteral& addrlit, Register d) {
- internal_sethi(addrlit, d, true);
-}
-
-
-int MacroAssembler::insts_for_sethi(address a, bool worst_case) {
- if (worst_case) return 7;
- intptr_t iaddr = (intptr_t) a;
- int msb32 = (int) (iaddr >> 32);
- int lsb32 = (int) (iaddr);
- int count;
- if (msb32 == 0 && lsb32 >= 0)
- count = 1;
- else if (msb32 == -1)
- count = 2;
- else {
- count = 2;
- if (msb32 & 0x3ff)
- count++;
- if (lsb32 & 0xFFFFFC00 ) {
- if ((lsb32 >> 20) & 0xfff) count += 2;
- if ((lsb32 >> 10) & 0x3ff) count += 2;
- }
- }
- return count;
-}
-
-int MacroAssembler::worst_case_insts_for_set() {
- return insts_for_sethi(NULL, true) + 1;
-}
-
-
-// Keep in sync with MacroAssembler::insts_for_internal_set
-void MacroAssembler::internal_set(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) {
- intptr_t value = addrlit.value();
-
- if (!ForceRelocatable && addrlit.rspec().type() == relocInfo::none) {
- // can optimize
- if (-4096 <= value && value <= 4095) {
- or3(G0, value, d); // setsw (this leaves upper 32 bits sign-extended)
- return;
- }
- if (inv_hi22(hi22(value)) == value) {
- sethi(addrlit, d);
- return;
- }
- }
- assert_no_delay("Cannot put two instructions in delay-slot.");
- internal_sethi(addrlit, d, ForceRelocatable);
- if (ForceRelocatable || addrlit.rspec().type() != relocInfo::none || addrlit.low10() != 0) {
- add(d, addrlit.low10(), d, addrlit.rspec());
- }
-}
-
-// Keep in sync with MacroAssembler::internal_set
-int MacroAssembler::insts_for_internal_set(intptr_t value) {
- // can optimize
- if (-4096 <= value && value <= 4095) {
- return 1;
- }
- if (inv_hi22(hi22(value)) == value) {
- return insts_for_sethi((address) value);
- }
- int count = insts_for_sethi((address) value);
- AddressLiteral al(value);
- if (al.low10() != 0) {
- count++;
- }
- return count;
-}
-
-void MacroAssembler::set(const AddressLiteral& al, Register d) {
- internal_set(al, d, false);
-}
-
-void MacroAssembler::set(intptr_t value, Register d) {
- AddressLiteral al(value);
- internal_set(al, d, false);
-}
-
-void MacroAssembler::set(address addr, Register d, RelocationHolder const& rspec) {
- AddressLiteral al(addr, rspec);
- internal_set(al, d, false);
-}
-
-void MacroAssembler::patchable_set(const AddressLiteral& al, Register d) {
- internal_set(al, d, true);
-}
-
-void MacroAssembler::patchable_set(intptr_t value, Register d) {
- AddressLiteral al(value);
- internal_set(al, d, true);
-}
-
-
-void MacroAssembler::set64(jlong value, Register d, Register tmp) {
- assert_not_delayed();
- v9_dep();
-
- int hi = (int)(value >> 32);
- int lo = (int)(value & ~0);
- int bits_33to2 = (int)((value >> 2) & ~0);
- // (Matcher::isSimpleConstant64 knows about the following optimizations.)
- if (Assembler::is_simm13(lo) && value == lo) {
- or3(G0, lo, d);
- } else if (hi == 0) {
- Assembler::sethi(lo, d); // hardware version zero-extends to upper 32
- if (low10(lo) != 0)
- or3(d, low10(lo), d);
- }
- else if ((hi >> 2) == 0) {
- Assembler::sethi(bits_33to2, d); // hardware version zero-extends to upper 32
- sllx(d, 2, d);
- if (low12(lo) != 0)
- or3(d, low12(lo), d);
- }
- else if (hi == -1) {
- Assembler::sethi(~lo, d); // hardware version zero-extends to upper 32
- xor3(d, low10(lo) ^ ~low10(~0), d);
- }
- else if (lo == 0) {
- if (Assembler::is_simm13(hi)) {
- or3(G0, hi, d);
- } else {
- Assembler::sethi(hi, d); // hardware version zero-extends to upper 32
- if (low10(hi) != 0)
- or3(d, low10(hi), d);
- }
- sllx(d, 32, d);
- }
- else {
- Assembler::sethi(hi, tmp);
- Assembler::sethi(lo, d); // macro assembler version sign-extends
- if (low10(hi) != 0)
- or3 (tmp, low10(hi), tmp);
- if (low10(lo) != 0)
- or3 ( d, low10(lo), d);
- sllx(tmp, 32, tmp);
- or3 (d, tmp, d);
- }
-}
-
-int MacroAssembler::insts_for_set64(jlong value) {
- v9_dep();
-
- int hi = (int) (value >> 32);
- int lo = (int) (value & ~0);
- int count = 0;
-
- // (Matcher::isSimpleConstant64 knows about the following optimizations.)
- if (Assembler::is_simm13(lo) && value == lo) {
- count++;
- } else if (hi == 0) {
- count++;
- if (low10(lo) != 0)
- count++;
- }
- else if (hi == -1) {
- count += 2;
- }
- else if (lo == 0) {
- if (Assembler::is_simm13(hi)) {
- count++;
- } else {
- count++;
- if (low10(hi) != 0)
- count++;
- }
- count++;
- }
- else {
- count += 2;
- if (low10(hi) != 0)
- count++;
- if (low10(lo) != 0)
- count++;
- count += 2;
- }
- return count;
-}
-
-// compute size in bytes of sparc frame, given
-// number of extraWords
-int MacroAssembler::total_frame_size_in_bytes(int extraWords) {
-
- int nWords = frame::memory_parameter_word_sp_offset;
-
- nWords += extraWords;
-
- if (nWords & 1) ++nWords; // round up to double-word
-
- return nWords * BytesPerWord;
-}
-
-
-// save_frame: given number of "extra" words in frame,
-// issue approp. save instruction (p 200, v8 manual)
-
-void MacroAssembler::save_frame(int extraWords) {
- int delta = -total_frame_size_in_bytes(extraWords);
- if (is_simm13(delta)) {
- save(SP, delta, SP);
- } else {
- set(delta, G3_scratch);
- save(SP, G3_scratch, SP);
- }
-}
-
-
-void MacroAssembler::save_frame_c1(int size_in_bytes) {
- if (is_simm13(-size_in_bytes)) {
- save(SP, -size_in_bytes, SP);
- } else {
- set(-size_in_bytes, G3_scratch);
- save(SP, G3_scratch, SP);
- }
-}
-
-
-void MacroAssembler::save_frame_and_mov(int extraWords,
- Register s1, Register d1,
- Register s2, Register d2) {
- assert_not_delayed();
-
- // The trick here is to use precisely the same memory word
- // that trap handlers also use to save the register.
- // This word cannot be used for any other purpose, but
- // it works fine to save the register's value, whether or not
- // an interrupt flushes register windows at any given moment!
- Address s1_addr;
- if (s1->is_valid() && (s1->is_in() || s1->is_local())) {
- s1_addr = s1->address_in_saved_window();
- st_ptr(s1, s1_addr);
- }
-
- Address s2_addr;
- if (s2->is_valid() && (s2->is_in() || s2->is_local())) {
- s2_addr = s2->address_in_saved_window();
- st_ptr(s2, s2_addr);
- }
-
- save_frame(extraWords);
-
- if (s1_addr.base() == SP) {
- ld_ptr(s1_addr.after_save(), d1);
- } else if (s1->is_valid()) {
- mov(s1->after_save(), d1);
- }
-
- if (s2_addr.base() == SP) {
- ld_ptr(s2_addr.after_save(), d2);
- } else if (s2->is_valid()) {
- mov(s2->after_save(), d2);
- }
-}
-
-
-AddressLiteral MacroAssembler::allocate_metadata_address(Metadata* obj) {
- assert(oop_recorder() != NULL, "this assembler needs a Recorder");
- int index = oop_recorder()->allocate_metadata_index(obj);
- RelocationHolder rspec = metadata_Relocation::spec(index);
- return AddressLiteral((address)obj, rspec);
-}
-
-AddressLiteral MacroAssembler::constant_metadata_address(Metadata* obj) {
- assert(oop_recorder() != NULL, "this assembler needs a Recorder");
- int index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = metadata_Relocation::spec(index);
- return AddressLiteral((address)obj, rspec);
-}
-
-
-AddressLiteral MacroAssembler::constant_oop_address(jobject obj) {
-#ifdef ASSERT
- {
- ThreadInVMfromUnknown tiv;
- assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
- assert(Universe::heap()->is_in(JNIHandles::resolve(obj)), "not an oop");
- }
-#endif
- int oop_index = oop_recorder()->find_index(obj);
- return AddressLiteral(obj, oop_Relocation::spec(oop_index));
-}
-
-void MacroAssembler::set_narrow_oop(jobject obj, Register d) {
- assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int oop_index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
-
- assert_not_delayed();
- // Relocation with special format (see relocInfo_sparc.hpp).
- relocate(rspec, 1);
- // Assembler::sethi(0x3fffff, d);
- emit_int32( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(0x3fffff) );
- // Don't add relocation for 'add'. Do patching during 'sethi' processing.
- add(d, 0x3ff, d);
-
-}
-
-void MacroAssembler::set_narrow_klass(Klass* k, Register d) {
- assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int klass_index = oop_recorder()->find_index(k);
- RelocationHolder rspec = metadata_Relocation::spec(klass_index);
- narrowOop encoded_k = CompressedKlassPointers::encode(k);
-
- assert_not_delayed();
- // Relocation with special format (see relocInfo_sparc.hpp).
- relocate(rspec, 1);
- // Assembler::sethi(encoded_k, d);
- emit_int32( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(encoded_k) );
- // Don't add relocation for 'add'. Do patching during 'sethi' processing.
- add(d, low10(encoded_k), d);
-
-}
-
-void MacroAssembler::align(int modulus) {
- while (offset() % modulus != 0) nop();
-}
-
-void RegistersForDebugging::print(outputStream* s) {
- FlagSetting fs(Debugging, true);
- int j;
- for (j = 0; j < 8; ++j) {
- if (j != 6) { s->print("i%d = ", j); os::print_location(s, i[j]); }
- else { s->print( "fp = " ); os::print_location(s, i[j]); }
- }
- s->cr();
-
- for (j = 0; j < 8; ++j) {
- s->print("l%d = ", j); os::print_location(s, l[j]);
- }
- s->cr();
-
- for (j = 0; j < 8; ++j) {
- if (j != 6) { s->print("o%d = ", j); os::print_location(s, o[j]); }
- else { s->print( "sp = " ); os::print_location(s, o[j]); }
- }
- s->cr();
-
- for (j = 0; j < 8; ++j) {
- s->print("g%d = ", j); os::print_location(s, g[j]);
- }
- s->cr();
-
- // print out floats with compression
- for (j = 0; j < 32; ) {
- jfloat val = f[j];
- int last = j;
- for ( ; last+1 < 32; ++last ) {
- char b1[1024], b2[1024];
- sprintf(b1, "%f", val);
- sprintf(b2, "%f", f[last+1]);
- if (strcmp(b1, b2))
- break;
- }
- s->print("f%d", j);
- if ( j != last ) s->print(" - f%d", last);
- s->print(" = %f", val);
- s->fill_to(25);
- s->print_cr(" (0x%x)", *(int*)&val);
- j = last + 1;
- }
- s->cr();
-
- // and doubles (evens only)
- for (j = 0; j < 32; ) {
- jdouble val = d[j];
- int last = j;
- for ( ; last+1 < 32; ++last ) {
- char b1[1024], b2[1024];
- sprintf(b1, "%f", val);
- sprintf(b2, "%f", d[last+1]);
- if (strcmp(b1, b2))
- break;
- }
- s->print("d%d", 2 * j);
- if ( j != last ) s->print(" - d%d", last);
- s->print(" = %f", val);
- s->fill_to(30);
- s->print("(0x%x)", *(int*)&val);
- s->fill_to(42);
- s->print_cr("(0x%x)", *(1 + (int*)&val));
- j = last + 1;
- }
- s->cr();
-}
-
-void RegistersForDebugging::save_registers(MacroAssembler* a) {
- a->sub(FP, align_up(sizeof(RegistersForDebugging), sizeof(jdouble)) - STACK_BIAS, O0);
- a->flushw();
- int i;
- for (i = 0; i < 8; ++i) {
- a->ld_ptr(as_iRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, i_offset(i));
- a->ld_ptr(as_lRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, l_offset(i));
- a->st_ptr(as_oRegister(i)->after_save(), O0, o_offset(i));
- a->st_ptr(as_gRegister(i)->after_save(), O0, g_offset(i));
- }
- for (i = 0; i < 32; ++i) {
- a->stf(FloatRegisterImpl::S, as_FloatRegister(i), O0, f_offset(i));
- }
- for (i = 0; i < 64; i += 2) {
- a->stf(FloatRegisterImpl::D, as_FloatRegister(i), O0, d_offset(i));
- }
-}
-
-void RegistersForDebugging::restore_registers(MacroAssembler* a, Register r) {
- for (int i = 1; i < 8; ++i) {
- a->ld_ptr(r, g_offset(i), as_gRegister(i));
- }
- for (int j = 0; j < 32; ++j) {
- a->ldf(FloatRegisterImpl::S, O0, f_offset(j), as_FloatRegister(j));
- }
- for (int k = 0; k < 64; k += 2) {
- a->ldf(FloatRegisterImpl::D, O0, d_offset(k), as_FloatRegister(k));
- }
-}
-
-void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * file, int line) {
- // plausibility check for oops
- if (!VerifyOops) return;
-
- if (reg == G0) return; // always NULL, which is always an oop
-
- BLOCK_COMMENT("verify_oop {");
- char buffer[64];
-#ifdef COMPILER1
- if (CommentedAssembly) {
- snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset());
- block_comment(buffer);
- }
-#endif
-
- const char* real_msg = NULL;
- {
- ResourceMark rm;
- stringStream ss;
- ss.print("%s at offset %d (%s:%d)", msg, offset(), file, line);
- real_msg = code_string(ss.as_string());
- }
-
- // Call indirectly to solve generation ordering problem
- AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
-
- // Make some space on stack above the current register window.
- // Enough to hold 8 64-bit registers.
- add(SP,-8*8,SP);
-
- // Save some 64-bit registers; a normal 'save' chops the heads off
- // of 64-bit longs in the 32-bit build.
- stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8);
- stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8);
- mov(reg,O0); // Move arg into O0; arg might be in O7 which is about to be crushed
- stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
-
- // Size of set() should stay the same
- patchable_set((intptr_t)real_msg, O1);
- // Load address to call to into O7
- load_ptr_contents(a, O7);
- // Register call to verify_oop_subroutine
- callr(O7, G0);
- delayed()->nop();
- // recover frame size
- add(SP, 8*8,SP);
- BLOCK_COMMENT("} verify_oop");
-}
-
-void MacroAssembler::_verify_oop_addr(Address addr, const char* msg, const char * file, int line) {
- // plausibility check for oops
- if (!VerifyOops) return;
-
- const char* real_msg = NULL;
- {
- ResourceMark rm;
- stringStream ss;
- ss.print("%s at SP+%d (%s:%d)", msg, addr.disp(), file, line);
- real_msg = code_string(ss.as_string());
- }
-
- // Call indirectly to solve generation ordering problem
- AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
-
- // Make some space on stack above the current register window.
- // Enough to hold 8 64-bit registers.
- add(SP,-8*8,SP);
-
- // Save some 64-bit registers; a normal 'save' chops the heads off
- // of 64-bit longs in the 32-bit build.
- stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8);
- stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8);
- ld_ptr(addr.base(), addr.disp() + 8*8, O0); // Load arg into O0; arg might be in O7 which is about to be crushed
- stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
-
- // Size of set() should stay the same
- patchable_set((intptr_t)real_msg, O1);
- // Load address to call to into O7
- load_ptr_contents(a, O7);
- // Register call to verify_oop_subroutine
- callr(O7, G0);
- delayed()->nop();
- // recover frame size
- add(SP, 8*8,SP);
-}
-
-// side-door communication with signalHandler in os_solaris.cpp
-address MacroAssembler::_verify_oop_implicit_branch[3] = { NULL };
-
-// This macro is expanded just once; it creates shared code. Contract:
-// receives an oop in O0. Must restore O0 & O7 from TLS. Must not smash ANY
-// registers, including flags. May not use a register 'save', as this blows
-// the high bits of the O-regs if they contain Long values. Acts as a 'leaf'
-// call.
-void MacroAssembler::verify_oop_subroutine() {
- // Leaf call; no frame.
- Label succeed, fail, null_or_fail;
-
- // O0 and O7 were saved already (O0 in O0's TLS home, O7 in O5's TLS home).
- // O0 is now the oop to be checked. O7 is the return address.
- Register O0_obj = O0;
-
- // Save some more registers for temps.
- stx(O2,SP,frame::register_save_words*wordSize+STACK_BIAS+2*8);
- stx(O3,SP,frame::register_save_words*wordSize+STACK_BIAS+3*8);
- stx(O4,SP,frame::register_save_words*wordSize+STACK_BIAS+4*8);
- stx(O5,SP,frame::register_save_words*wordSize+STACK_BIAS+5*8);
-
- // Save flags
- Register O5_save_flags = O5;
- rdccr( O5_save_flags );
-
- { // count number of verifies
- Register O2_adr = O2;
- Register O3_accum = O3;
- inc_counter(StubRoutines::verify_oop_count_addr(), O2_adr, O3_accum);
- }
-
- Register O2_mask = O2;
- Register O3_bits = O3;
- Register O4_temp = O4;
-
- // mark lower end of faulting range
- assert(_verify_oop_implicit_branch[0] == NULL, "set once");
- _verify_oop_implicit_branch[0] = pc();
-
- // We can't check the mark oop because it could be in the process of
- // locking or unlocking while this is running.
- set(Universe::verify_oop_mask (), O2_mask);
- set(Universe::verify_oop_bits (), O3_bits);
-
- // assert((obj & oop_mask) == oop_bits);
- and3(O0_obj, O2_mask, O4_temp);
- cmp_and_brx_short(O4_temp, O3_bits, notEqual, pn, null_or_fail);
-
- if ((NULL_WORD & Universe::verify_oop_mask()) == Universe::verify_oop_bits()) {
- // the null_or_fail case is useless; must test for null separately
- br_null_short(O0_obj, pn, succeed);
- }
-
- // Check the Klass* of this object for being in the right area of memory.
- // Cannot do the load in the delay above slot in case O0 is null
- load_klass(O0_obj, O0_obj);
- // assert((klass != NULL)
- br_null_short(O0_obj, pn, fail);
-
- wrccr( O5_save_flags ); // Restore CCR's
-
- // mark upper end of faulting range
- _verify_oop_implicit_branch[1] = pc();
-
- //-----------------------
- // all tests pass
- bind(succeed);
-
- // Restore prior 64-bit registers
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+0*8,O0);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+1*8,O1);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+2*8,O2);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+3*8,O3);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+4*8,O4);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+5*8,O5);
-
- retl(); // Leaf return; restore prior O7 in delay slot
- delayed()->ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+7*8,O7);
-
- //-----------------------
- bind(null_or_fail); // nulls are less common but OK
- br_null(O0_obj, false, pt, succeed);
- delayed()->wrccr( O5_save_flags ); // Restore CCR's
-
- //-----------------------
- // report failure:
- bind(fail);
- _verify_oop_implicit_branch[2] = pc();
-
- wrccr( O5_save_flags ); // Restore CCR's
-
- save_frame(align_up(sizeof(RegistersForDebugging) / BytesPerWord, 2));
-
- // stop_subroutine expects message pointer in I1.
- mov(I1, O1);
-
- // Restore prior 64-bit registers
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+0*8,I0);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+1*8,I1);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+2*8,I2);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+3*8,I3);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+4*8,I4);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+5*8,I5);
-
- // factor long stop-sequence into subroutine to save space
- assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet");
-
- // call indirectly to solve generation ordering problem
- AddressLiteral al(StubRoutines::Sparc::stop_subroutine_entry_address());
- load_ptr_contents(al, O5);
- jmpl(O5, 0, O7);
- delayed()->nop();
-}
-
-
-void MacroAssembler::stop(const char* msg) {
- // save frame first to get O7 for return address
- // add one word to size in case struct is odd number of words long
- // It must be doubleword-aligned for storing doubles into it.
-
- save_frame(align_up(sizeof(RegistersForDebugging) / BytesPerWord, 2));
-
- // stop_subroutine expects message pointer in I1.
- // Size of set() should stay the same
- patchable_set((intptr_t)msg, O1);
-
- // factor long stop-sequence into subroutine to save space
- assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet");
-
- // call indirectly to solve generation ordering problem
- AddressLiteral a(StubRoutines::Sparc::stop_subroutine_entry_address());
- load_ptr_contents(a, O5);
- jmpl(O5, 0, O7);
- delayed()->nop();
-
- breakpoint_trap(); // make stop actually stop rather than writing
- // unnoticeable results in the output files.
-
- // restore(); done in callee to save space!
-}
-
-
-void MacroAssembler::warn(const char* msg) {
- save_frame(align_up(sizeof(RegistersForDebugging) / BytesPerWord, 2));
- RegistersForDebugging::save_registers(this);
- mov(O0, L0);
- // Size of set() should stay the same
- patchable_set((intptr_t)msg, O0);
- call( CAST_FROM_FN_PTR(address, warning) );
- delayed()->nop();
-// ret();
-// delayed()->restore();
- RegistersForDebugging::restore_registers(this, L0);
- restore();
-}
-
-
-void MacroAssembler::untested(const char* what) {
- // We must be able to turn interactive prompting off
- // in order to run automated test scripts on the VM
- // Use the flag ShowMessageBoxOnError
-
- const char* b = NULL;
- {
- ResourceMark rm;
- stringStream ss;
- ss.print("untested: %s", what);
- b = code_string(ss.as_string());
- }
- if (ShowMessageBoxOnError) { STOP(b); }
- else { warn(b); }
-}
-
-
-void MacroAssembler::unimplemented(const char* what) {
- const char* buf = NULL;
- {
- ResourceMark rm;
- stringStream ss;
- ss.print("unimplemented: %s", what);
- buf = code_string(ss.as_string());
- }
- stop(buf);
-}
-
-
-void MacroAssembler::stop_subroutine() {
- RegistersForDebugging::save_registers(this);
-
- // for the sake of the debugger, stick a PC on the current frame
- // (this assumes that the caller has performed an extra "save")
- mov(I7, L7);
- add(O7, -7 * BytesPerInt, I7);
-
- save_frame(); // one more save to free up another O7 register
- mov(I0, O1); // addr of reg save area
-
- // We expect pointer to message in I1. Caller must set it up in O1
- mov(I1, O0); // get msg
- call (CAST_FROM_FN_PTR(address, MacroAssembler::debug), relocInfo::runtime_call_type);
- delayed()->nop();
-
- restore();
-
- RegistersForDebugging::restore_registers(this, O0);
-
- save_frame(0);
- call(CAST_FROM_FN_PTR(address,breakpoint));
- delayed()->nop();
- restore();
-
- mov(L7, I7);
- retl();
- delayed()->restore(); // see stop above
-}
-
-
-void MacroAssembler::debug(char* msg, RegistersForDebugging* regs) {
- if ( ShowMessageBoxOnError ) {
- JavaThread* thread = JavaThread::current();
- JavaThreadState saved_state = thread->thread_state();
- thread->set_thread_state(_thread_in_vm);
- {
- // In order to get locks work, we need to fake a in_VM state
- ttyLocker ttyl;
- ::tty->print_cr("EXECUTION STOPPED: %s\n", msg);
- if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
- BytecodeCounter::print();
- }
- if (os::message_box(msg, "Execution stopped, print registers?"))
- regs->print(::tty);
- }
- BREAKPOINT;
- ThreadStateTransition::transition(JavaThread::current(), _thread_in_vm, saved_state);
- }
- else {
- ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
- }
- assert(false, "DEBUG MESSAGE: %s", msg);
-}
-
-
-void MacroAssembler::calc_mem_param_words(Register Rparam_words, Register Rresult) {
- subcc( Rparam_words, Argument::n_register_parameters, Rresult); // how many mem words?
- Label no_extras;
- br( negative, true, pt, no_extras ); // if neg, clear reg
- delayed()->set(0, Rresult); // annuled, so only if taken
- bind( no_extras );
-}
-
-
-void MacroAssembler::calc_frame_size(Register Rextra_words, Register Rresult) {
- add(Rextra_words, frame::memory_parameter_word_sp_offset, Rresult);
- bclr(1, Rresult);
- sll(Rresult, LogBytesPerWord, Rresult); // Rresult has total frame bytes
-}
-
-
-void MacroAssembler::calc_frame_size_and_save(Register Rextra_words, Register Rresult) {
- calc_frame_size(Rextra_words, Rresult);
- neg(Rresult);
- save(SP, Rresult, SP);
-}
-
-
-// ---------------------------------------------------------
-Assembler::RCondition cond2rcond(Assembler::Condition c) {
- switch (c) {
- /*case zero: */
- case Assembler::equal: return Assembler::rc_z;
- case Assembler::lessEqual: return Assembler::rc_lez;
- case Assembler::less: return Assembler::rc_lz;
- /*case notZero:*/
- case Assembler::notEqual: return Assembler::rc_nz;
- case Assembler::greater: return Assembler::rc_gz;
- case Assembler::greaterEqual: return Assembler::rc_gez;
- }
- ShouldNotReachHere();
- return Assembler::rc_z;
-}
-
-// compares (32 bit) register with zero and branches. NOT FOR USE WITH 64-bit POINTERS
-void MacroAssembler::cmp_zero_and_br(Condition c, Register s1, Label& L, bool a, Predict p) {
- tst(s1);
- br (c, a, p, L);
-}
-
-// Compares a pointer register with zero and branches on null.
-// Does a test & branch on 32-bit systems and a register-branch on 64-bit.
-void MacroAssembler::br_null( Register s1, bool a, Predict p, Label& L ) {
- assert_not_delayed();
- bpr( rc_z, a, p, s1, L );
-}
-
-void MacroAssembler::br_notnull( Register s1, bool a, Predict p, Label& L ) {
- assert_not_delayed();
- bpr( rc_nz, a, p, s1, L );
-}
-
-// Compare registers and branch with nop in delay slot or cbcond without delay slot.
-
-// Compare integer (32 bit) values (icc only).
-void MacroAssembler::cmp_and_br_short(Register s1, Register s2, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(c, icc, s1, s2, L);
- } else {
- cmp(s1, s2);
- br(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Compare integer (32 bit) values (icc only).
-void MacroAssembler::cmp_and_br_short(Register s1, int simm13a, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (is_simm(simm13a,5) && use_cbcond(L)) {
- Assembler::cbcond(c, icc, s1, simm13a, L);
- } else {
- cmp(s1, simm13a);
- br(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Branch that tests xcc in LP64 and icc in !LP64
-void MacroAssembler::cmp_and_brx_short(Register s1, Register s2, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(c, ptr_cc, s1, s2, L);
- } else {
- cmp(s1, s2);
- brx(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Branch that tests xcc in LP64 and icc in !LP64
-void MacroAssembler::cmp_and_brx_short(Register s1, int simm13a, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (is_simm(simm13a,5) && use_cbcond(L)) {
- Assembler::cbcond(c, ptr_cc, s1, simm13a, L);
- } else {
- cmp(s1, simm13a);
- brx(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Short branch version for compares a pointer with zero.
-
-void MacroAssembler::br_null_short(Register s1, Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(zero, ptr_cc, s1, 0, L);
- } else {
- br_null(s1, false, p, L);
- delayed()->nop();
- }
-}
-
-void MacroAssembler::br_notnull_short(Register s1, Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(notZero, ptr_cc, s1, 0, L);
- } else {
- br_notnull(s1, false, p, L);
- delayed()->nop();
- }
-}
-
-// Unconditional short branch
-void MacroAssembler::ba_short(Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(equal, icc, G0, G0, L);
- } else {
- br(always, false, pt, L);
- delayed()->nop();
- }
-}
-
-// Branch if 'icc' says zero or not (i.e. icc.z == 1|0).
-
-void MacroAssembler::br_icc_zero(bool iszero, Predict p, Label &L) {
- assert_not_delayed();
- Condition cf = (iszero ? Assembler::zero : Assembler::notZero);
- br(cf, false, p, L);
- delayed()->nop();
-}
-
-// instruction sequences factored across compiler & interpreter
-
-
-void MacroAssembler::lcmp( Register Ra_hi, Register Ra_low,
- Register Rb_hi, Register Rb_low,
- Register Rresult) {
-
- Label check_low_parts, done;
-
- cmp(Ra_hi, Rb_hi ); // compare hi parts
- br(equal, true, pt, check_low_parts);
- delayed()->cmp(Ra_low, Rb_low); // test low parts
-
- // And, with an unsigned comparison, it does not matter if the numbers
- // are negative or not.
- // E.g., -2 cmp -1: the low parts are 0xfffffffe and 0xffffffff.
- // The second one is bigger (unsignedly).
-
- // Other notes: The first move in each triplet can be unconditional
- // (and therefore probably prefetchable).
- // And the equals case for the high part does not need testing,
- // since that triplet is reached only after finding the high halves differ.
-
- mov(-1, Rresult);
- ba(done);
- delayed()->movcc(greater, false, icc, 1, Rresult);
-
- bind(check_low_parts);
-
- mov( -1, Rresult);
- movcc(equal, false, icc, 0, Rresult);
- movcc(greaterUnsigned, false, icc, 1, Rresult);
-
- bind(done);
-}
-
-void MacroAssembler::lneg( Register Rhi, Register Rlow ) {
- subcc( G0, Rlow, Rlow );
- subc( G0, Rhi, Rhi );
-}
-
-void MacroAssembler::lshl( Register Rin_high, Register Rin_low,
- Register Rcount,
- Register Rout_high, Register Rout_low,
- Register Rtemp ) {
-
-
- Register Ralt_count = Rtemp;
- Register Rxfer_bits = Rtemp;
-
- assert( Ralt_count != Rin_high
- && Ralt_count != Rin_low
- && Ralt_count != Rcount
- && Rxfer_bits != Rin_low
- && Rxfer_bits != Rin_high
- && Rxfer_bits != Rcount
- && Rxfer_bits != Rout_low
- && Rout_low != Rin_high,
- "register alias checks");
-
- Label big_shift, done;
-
- // This code can be optimized to use the 64 bit shifts in V9.
- // Here we use the 32 bit shifts.
-
- and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
- subcc(Rcount, 31, Ralt_count);
- br(greater, true, pn, big_shift);
- delayed()->dec(Ralt_count);
-
- // shift < 32 bits, Ralt_count = Rcount-31
-
- // We get the transfer bits by shifting right by 32-count the low
- // register. This is done by shifting right by 31-count and then by one
- // more to take care of the special (rare) case where count is zero
- // (shifting by 32 would not work).
-
- neg(Ralt_count);
-
- // The order of the next two instructions is critical in the case where
- // Rin and Rout are the same and should not be reversed.
-
- srl(Rin_low, Ralt_count, Rxfer_bits); // shift right by 31-count
- if (Rcount != Rout_low) {
- sll(Rin_low, Rcount, Rout_low); // low half
- }
- sll(Rin_high, Rcount, Rout_high);
- if (Rcount == Rout_low) {
- sll(Rin_low, Rcount, Rout_low); // low half
- }
- srl(Rxfer_bits, 1, Rxfer_bits ); // shift right by one more
- ba(done);
- delayed()->or3(Rout_high, Rxfer_bits, Rout_high); // new hi value: or in shifted old hi part and xfer from low
-
- // shift >= 32 bits, Ralt_count = Rcount-32
- bind(big_shift);
- sll(Rin_low, Ralt_count, Rout_high );
- clr(Rout_low);
-
- bind(done);
-}
-
-
-void MacroAssembler::lshr( Register Rin_high, Register Rin_low,
- Register Rcount,
- Register Rout_high, Register Rout_low,
- Register Rtemp ) {
-
- Register Ralt_count = Rtemp;
- Register Rxfer_bits = Rtemp;
-
- assert( Ralt_count != Rin_high
- && Ralt_count != Rin_low
- && Ralt_count != Rcount
- && Rxfer_bits != Rin_low
- && Rxfer_bits != Rin_high
- && Rxfer_bits != Rcount
- && Rxfer_bits != Rout_high
- && Rout_high != Rin_low,
- "register alias checks");
-
- Label big_shift, done;
-
- // This code can be optimized to use the 64 bit shifts in V9.
- // Here we use the 32 bit shifts.
-
- and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
- subcc(Rcount, 31, Ralt_count);
- br(greater, true, pn, big_shift);
- delayed()->dec(Ralt_count);
-
- // shift < 32 bits, Ralt_count = Rcount-31
-
- // We get the transfer bits by shifting left by 32-count the high
- // register. This is done by shifting left by 31-count and then by one
- // more to take care of the special (rare) case where count is zero
- // (shifting by 32 would not work).
-
- neg(Ralt_count);
- if (Rcount != Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
-
- // The order of the next two instructions is critical in the case where
- // Rin and Rout are the same and should not be reversed.
-
- sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count
- sra(Rin_high, Rcount, Rout_high ); // high half
- sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more
- if (Rcount == Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
- ba(done);
- delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high
-
- // shift >= 32 bits, Ralt_count = Rcount-32
- bind(big_shift);
-
- sra(Rin_high, Ralt_count, Rout_low);
- sra(Rin_high, 31, Rout_high); // sign into hi
-
- bind( done );
-}
-
-
-
-void MacroAssembler::lushr( Register Rin_high, Register Rin_low,
- Register Rcount,
- Register Rout_high, Register Rout_low,
- Register Rtemp ) {
-
- Register Ralt_count = Rtemp;
- Register Rxfer_bits = Rtemp;
-
- assert( Ralt_count != Rin_high
- && Ralt_count != Rin_low
- && Ralt_count != Rcount
- && Rxfer_bits != Rin_low
- && Rxfer_bits != Rin_high
- && Rxfer_bits != Rcount
- && Rxfer_bits != Rout_high
- && Rout_high != Rin_low,
- "register alias checks");
-
- Label big_shift, done;
-
- // This code can be optimized to use the 64 bit shifts in V9.
- // Here we use the 32 bit shifts.
-
- and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
- subcc(Rcount, 31, Ralt_count);
- br(greater, true, pn, big_shift);
- delayed()->dec(Ralt_count);
-
- // shift < 32 bits, Ralt_count = Rcount-31
-
- // We get the transfer bits by shifting left by 32-count the high
- // register. This is done by shifting left by 31-count and then by one
- // more to take care of the special (rare) case where count is zero
- // (shifting by 32 would not work).
-
- neg(Ralt_count);
- if (Rcount != Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
-
- // The order of the next two instructions is critical in the case where
- // Rin and Rout are the same and should not be reversed.
-
- sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count
- srl(Rin_high, Rcount, Rout_high ); // high half
- sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more
- if (Rcount == Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
- ba(done);
- delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high
-
- // shift >= 32 bits, Ralt_count = Rcount-32
- bind(big_shift);
-
- srl(Rin_high, Ralt_count, Rout_low);
- clr(Rout_high);
-
- bind( done );
-}
-
-void MacroAssembler::lcmp( Register Ra, Register Rb, Register Rresult) {
- cmp(Ra, Rb);
- mov(-1, Rresult);
- movcc(equal, false, xcc, 0, Rresult);
- movcc(greater, false, xcc, 1, Rresult);
-}
-
-
-void MacroAssembler::load_sized_value(Address src, Register dst, size_t size_in_bytes, bool is_signed) {
- switch (size_in_bytes) {
- case 8: ld_long(src, dst); break;
- case 4: ld( src, dst); break;
- case 2: is_signed ? ldsh(src, dst) : lduh(src, dst); break;
- case 1: is_signed ? ldsb(src, dst) : ldub(src, dst); break;
- default: ShouldNotReachHere();
- }
-}
-
-void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in_bytes) {
- switch (size_in_bytes) {
- case 8: st_long(src, dst); break;
- case 4: st( src, dst); break;
- case 2: sth( src, dst); break;
- case 1: stb( src, dst); break;
- default: ShouldNotReachHere();
- }
-}
-
-
-void MacroAssembler::float_cmp( bool is_float, int unordered_result,
- FloatRegister Fa, FloatRegister Fb,
- Register Rresult) {
- if (is_float) {
- fcmp(FloatRegisterImpl::S, fcc0, Fa, Fb);
- } else {
- fcmp(FloatRegisterImpl::D, fcc0, Fa, Fb);
- }
-
- if (unordered_result == 1) {
- mov( -1, Rresult);
- movcc(f_equal, true, fcc0, 0, Rresult);
- movcc(f_unorderedOrGreater, true, fcc0, 1, Rresult);
- } else {
- mov( -1, Rresult);
- movcc(f_equal, true, fcc0, 0, Rresult);
- movcc(f_greater, true, fcc0, 1, Rresult);
- }
-}
-
-
-void MacroAssembler::save_all_globals_into_locals() {
- mov(G1,L1);
- mov(G2,L2);
- mov(G3,L3);
- mov(G4,L4);
- mov(G5,L5);
- mov(G6,L6);
- mov(G7,L7);
-}
-
-void MacroAssembler::restore_globals_from_locals() {
- mov(L1,G1);
- mov(L2,G2);
- mov(L3,G3);
- mov(L4,G4);
- mov(L5,G5);
- mov(L6,G6);
- mov(L7,G7);
-}
-
-RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
- Register tmp,
- int offset) {
- intptr_t value = *delayed_value_addr;
- if (value != 0)
- return RegisterOrConstant(value + offset);
-
- // load indirectly to solve generation ordering problem
- AddressLiteral a(delayed_value_addr);
- load_ptr_contents(a, tmp);
-
-#ifdef ASSERT
- tst(tmp);
- breakpoint_trap(zero, xcc);
-#endif
-
- if (offset != 0)
- add(tmp, offset, tmp);
-
- return RegisterOrConstant(tmp);
-}
-
-
-RegisterOrConstant MacroAssembler::regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
- assert(d.register_or_noreg() != G0, "lost side effect");
- if ((s2.is_constant() && s2.as_constant() == 0) ||
- (s2.is_register() && s2.as_register() == G0)) {
- // Do nothing, just move value.
- if (s1.is_register()) {
- if (d.is_constant()) d = temp;
- mov(s1.as_register(), d.as_register());
- return d;
- } else {
- return s1;
- }
- }
-
- if (s1.is_register()) {
- assert_different_registers(s1.as_register(), temp);
- if (d.is_constant()) d = temp;
- andn(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
- return d;
- } else {
- if (s2.is_register()) {
- assert_different_registers(s2.as_register(), temp);
- if (d.is_constant()) d = temp;
- set(s1.as_constant(), temp);
- andn(temp, s2.as_register(), d.as_register());
- return d;
- } else {
- intptr_t res = s1.as_constant() & ~s2.as_constant();
- return res;
- }
- }
-}
-
-RegisterOrConstant MacroAssembler::regcon_inc_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
- assert(d.register_or_noreg() != G0, "lost side effect");
- if ((s2.is_constant() && s2.as_constant() == 0) ||
- (s2.is_register() && s2.as_register() == G0)) {
- // Do nothing, just move value.
- if (s1.is_register()) {
- if (d.is_constant()) d = temp;
- mov(s1.as_register(), d.as_register());
- return d;
- } else {
- return s1;
- }
- }
-
- if (s1.is_register()) {
- assert_different_registers(s1.as_register(), temp);
- if (d.is_constant()) d = temp;
- add(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
- return d;
- } else {
- if (s2.is_register()) {
- assert_different_registers(s2.as_register(), temp);
- if (d.is_constant()) d = temp;
- add(s2.as_register(), ensure_simm13_or_reg(s1, temp), d.as_register());
- return d;
- } else {
- intptr_t res = s1.as_constant() + s2.as_constant();
- return res;
- }
- }
-}
-
-RegisterOrConstant MacroAssembler::regcon_sll_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
- assert(d.register_or_noreg() != G0, "lost side effect");
- if (!is_simm13(s2.constant_or_zero()))
- s2 = (s2.as_constant() & 0xFF);
- if ((s2.is_constant() && s2.as_constant() == 0) ||
- (s2.is_register() && s2.as_register() == G0)) {
- // Do nothing, just move value.
- if (s1.is_register()) {
- if (d.is_constant()) d = temp;
- mov(s1.as_register(), d.as_register());
- return d;
- } else {
- return s1;
- }
- }
-
- if (s1.is_register()) {
- assert_different_registers(s1.as_register(), temp);
- if (d.is_constant()) d = temp;
- sll_ptr(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
- return d;
- } else {
- if (s2.is_register()) {
- assert_different_registers(s2.as_register(), temp);
- if (d.is_constant()) d = temp;
- set(s1.as_constant(), temp);
- sll_ptr(temp, s2.as_register(), d.as_register());
- return d;
- } else {
- intptr_t res = s1.as_constant() << s2.as_constant();
- return res;
- }
- }
-}
-
-
-// Look up the method for a megamorphic invokeinterface call.
-// The target method is determined by .
-// The receiver klass is in recv_klass.
-// On success, the result will be in method_result, and execution falls through.
-// On failure, execution transfers to the given label.
-void MacroAssembler::lookup_interface_method(Register recv_klass,
- Register intf_klass,
- RegisterOrConstant itable_index,
- Register method_result,
- Register scan_temp,
- Register sethi_temp,
- Label& L_no_such_interface,
- bool return_method) {
- assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
- assert(!return_method || itable_index.is_constant() || itable_index.as_register() == method_result,
- "caller must use same register for non-constant itable index as for method");
-
- Label L_no_such_interface_restore;
- bool did_save = false;
- if (scan_temp == noreg || sethi_temp == noreg) {
- Register recv_2 = recv_klass->is_global() ? recv_klass : L0;
- Register intf_2 = intf_klass->is_global() ? intf_klass : L1;
- assert(method_result->is_global(), "must be able to return value");
- scan_temp = L2;
- sethi_temp = L3;
- save_frame_and_mov(0, recv_klass, recv_2, intf_klass, intf_2);
- recv_klass = recv_2;
- intf_klass = intf_2;
- did_save = true;
- }
-
- // Compute start of first itableOffsetEntry (which is at the end of the vtable)
- int vtable_base = in_bytes(Klass::vtable_start_offset());
- int scan_step = itableOffsetEntry::size() * wordSize;
- int vte_size = vtableEntry::size_in_bytes();
-
- lduw(recv_klass, in_bytes(Klass::vtable_length_offset()), scan_temp);
- // %%% We should store the aligned, prescaled offset in the klassoop.
- // Then the next several instructions would fold away.
-
- int itb_offset = vtable_base;
- int itb_scale = exact_log2(vtableEntry::size_in_bytes());
- sll(scan_temp, itb_scale, scan_temp);
- add(scan_temp, itb_offset, scan_temp);
- add(recv_klass, scan_temp, scan_temp);
-
- if (return_method) {
- // Adjust recv_klass by scaled itable_index, so we can free itable_index.
- RegisterOrConstant itable_offset = itable_index;
- itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset);
- itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset);
- add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass);
- }
-
- // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
- // if (scan->interface() == intf) {
- // result = (klass + scan->offset() + itable_index);
- // }
- // }
- Label L_search, L_found_method;
-
- for (int peel = 1; peel >= 0; peel--) {
- // %%%% Could load both offset and interface in one ldx, if they were
- // in the opposite order. This would save a load.
- ld_ptr(scan_temp, itableOffsetEntry::interface_offset_in_bytes(), method_result);
-
- // Check that this entry is non-null. A null entry means that
- // the receiver class doesn't implement the interface, and wasn't the
- // same as when the caller was compiled.
- bpr(Assembler::rc_z, false, Assembler::pn, method_result, did_save ? L_no_such_interface_restore : L_no_such_interface);
- delayed()->cmp(method_result, intf_klass);
-
- if (peel) {
- brx(Assembler::equal, false, Assembler::pt, L_found_method);
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, L_search);
- // (invert the test to fall through to found_method...)
- }
- delayed()->add(scan_temp, scan_step, scan_temp);
-
- if (!peel) break;
-
- bind(L_search);
- }
-
- bind(L_found_method);
-
- if (return_method) {
- // Got a hit.
- int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
- // scan_temp[-scan_step] points to the vtable offset we need
- ito_offset -= scan_step;
- lduw(scan_temp, ito_offset, scan_temp);
- ld_ptr(recv_klass, scan_temp, method_result);
- }
-
- if (did_save) {
- Label L_done;
- ba(L_done);
- delayed()->restore();
-
- bind(L_no_such_interface_restore);
- ba(L_no_such_interface);
- delayed()->restore();
-
- bind(L_done);
- }
-}
-
-
-// virtual method calling
-void MacroAssembler::lookup_virtual_method(Register recv_klass,
- RegisterOrConstant vtable_index,
- Register method_result) {
- assert_different_registers(recv_klass, method_result, vtable_index.register_or_noreg());
- Register sethi_temp = method_result;
- const int base = in_bytes(Klass::vtable_start_offset()) +
- // method pointer offset within the vtable entry:
- vtableEntry::method_offset_in_bytes();
- RegisterOrConstant vtable_offset = vtable_index;
- // Each of the following three lines potentially generates an instruction.
- // But the total number of address formation instructions will always be
- // at most two, and will often be zero. In any case, it will be optimal.
- // If vtable_index is a register, we will have (sll_ptr N,x; inc_ptr B,x; ld_ptr k,x).
- // If vtable_index is a constant, we will have at most (set B+X<is_global()) sub_2 = L0;
- if (!sup_2->is_global()) sup_2 = L1;
- bool did_save = false;
- if (temp_reg == noreg || temp2_reg == noreg) {
- temp_reg = L2;
- temp2_reg = L3;
- save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2);
- sub_klass = sub_2;
- super_klass = sup_2;
- did_save = true;
- }
- Label L_failure, L_pop_to_failure, L_pop_to_success;
- check_klass_subtype_fast_path(sub_klass, super_klass,
- temp_reg, temp2_reg,
- (did_save ? &L_pop_to_success : &L_success),
- (did_save ? &L_pop_to_failure : &L_failure), NULL);
-
- if (!did_save)
- save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2);
- check_klass_subtype_slow_path(sub_2, sup_2,
- L2, L3, L4, L5,
- NULL, &L_pop_to_failure);
-
- // on success:
- bind(L_pop_to_success);
- restore();
- ba_short(L_success);
-
- // on failure:
- bind(L_pop_to_failure);
- restore();
- bind(L_failure);
-}
-
-
-void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label* L_success,
- Label* L_failure,
- Label* L_slow_path,
- RegisterOrConstant super_check_offset) {
- int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
- int sco_offset = in_bytes(Klass::super_check_offset_offset());
-
- bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
- bool need_slow_path = (must_load_sco ||
- super_check_offset.constant_or_zero() == sco_offset);
-
- assert_different_registers(sub_klass, super_klass, temp_reg);
- if (super_check_offset.is_register()) {
- assert_different_registers(sub_klass, super_klass, temp_reg,
- super_check_offset.as_register());
- } else if (must_load_sco) {
- assert(temp2_reg != noreg, "supply either a temp or a register offset");
- }
-
- Label L_fallthrough;
- int label_nulls = 0;
- if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
- if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
- if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
- assert(label_nulls <= 1 ||
- (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path),
- "at most one NULL in the batch, usually");
-
- // If the pointers are equal, we are done (e.g., String[] elements).
- // This self-check enables sharing of secondary supertype arrays among
- // non-primary types such as array-of-interface. Otherwise, each such
- // type would need its own customized SSA.
- // We move this check to the front of the fast path because many
- // type checks are in fact trivially successful in this manner,
- // so we get a nicely predicted branch right at the start of the check.
- cmp(super_klass, sub_klass);
- brx(Assembler::equal, false, Assembler::pn, *L_success);
- delayed()->nop();
-
- // Check the supertype display:
- if (must_load_sco) {
- // The super check offset is always positive...
- lduw(super_klass, sco_offset, temp2_reg);
- super_check_offset = RegisterOrConstant(temp2_reg);
- // super_check_offset is register.
- assert_different_registers(sub_klass, super_klass, temp_reg, super_check_offset.as_register());
- }
- ld_ptr(sub_klass, super_check_offset, temp_reg);
- cmp(super_klass, temp_reg);
-
- // This check has worked decisively for primary supers.
- // Secondary supers are sought in the super_cache ('super_cache_addr').
- // (Secondary supers are interfaces and very deeply nested subtypes.)
- // This works in the same check above because of a tricky aliasing
- // between the super_cache and the primary super display elements.
- // (The 'super_check_addr' can address either, as the case requires.)
- // Note that the cache is updated below if it does not help us find
- // what we need immediately.
- // So if it was a primary super, we can just fail immediately.
- // Otherwise, it's the slow path for us (no success at this point).
-
- // Hacked ba(), which may only be used just before L_fallthrough.
-#define FINAL_JUMP(label) \
- if (&(label) != &L_fallthrough) { \
- ba(label); delayed()->nop(); \
- }
-
- if (super_check_offset.is_register()) {
- brx(Assembler::equal, false, Assembler::pn, *L_success);
- delayed()->cmp(super_check_offset.as_register(), sc_offset);
-
- if (L_failure == &L_fallthrough) {
- brx(Assembler::equal, false, Assembler::pt, *L_slow_path);
- delayed()->nop();
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, *L_failure);
- delayed()->nop();
- FINAL_JUMP(*L_slow_path);
- }
- } else if (super_check_offset.as_constant() == sc_offset) {
- // Need a slow path; fast failure is impossible.
- if (L_slow_path == &L_fallthrough) {
- brx(Assembler::equal, false, Assembler::pt, *L_success);
- delayed()->nop();
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, *L_slow_path);
- delayed()->nop();
- FINAL_JUMP(*L_success);
- }
- } else {
- // No slow path; it's a fast decision.
- if (L_failure == &L_fallthrough) {
- brx(Assembler::equal, false, Assembler::pt, *L_success);
- delayed()->nop();
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, *L_failure);
- delayed()->nop();
- FINAL_JUMP(*L_success);
- }
- }
-
- bind(L_fallthrough);
-
-#undef FINAL_JUMP
-}
-
-
-void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
- Register super_klass,
- Register count_temp,
- Register scan_temp,
- Register scratch_reg,
- Register coop_reg,
- Label* L_success,
- Label* L_failure) {
- assert_different_registers(sub_klass, super_klass,
- count_temp, scan_temp, scratch_reg, coop_reg);
-
- Label L_fallthrough, L_loop;
- int label_nulls = 0;
- if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
- if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
- assert(label_nulls <= 1, "at most one NULL in the batch");
-
- // a couple of useful fields in sub_klass:
- int ss_offset = in_bytes(Klass::secondary_supers_offset());
- int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
-
- // Do a linear scan of the secondary super-klass chain.
- // This code is rarely used, so simplicity is a virtue here.
-
-#ifndef PRODUCT
- int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
- inc_counter((address) pst_counter, count_temp, scan_temp);
-#endif
-
- // We will consult the secondary-super array.
- ld_ptr(sub_klass, ss_offset, scan_temp);
-
- Register search_key = super_klass;
-
- // Load the array length. (Positive movl does right thing on LP64.)
- lduw(scan_temp, Array::length_offset_in_bytes(), count_temp);
-
- // Check for empty secondary super list
- tst(count_temp);
-
- // In the array of super classes elements are pointer sized.
- int element_size = wordSize;
-
- // Top of search loop
- bind(L_loop);
- br(Assembler::equal, false, Assembler::pn, *L_failure);
- delayed()->add(scan_temp, element_size, scan_temp);
-
- // Skip the array header in all array accesses.
- int elem_offset = Array::base_offset_in_bytes();
- elem_offset -= element_size; // the scan pointer was pre-incremented also
-
- // Load next super to check
- ld_ptr( scan_temp, elem_offset, scratch_reg );
-
- // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
- cmp(scratch_reg, search_key);
-
- // A miss means we are NOT a subtype and need to keep looping
- brx(Assembler::notEqual, false, Assembler::pn, L_loop);
- delayed()->deccc(count_temp); // decrement trip counter in delay slot
-
- // Success. Cache the super we found and proceed in triumph.
- st_ptr(super_klass, sub_klass, sc_offset);
-
- if (L_success != &L_fallthrough) {
- ba(*L_success);
- delayed()->nop();
- }
-
- bind(L_fallthrough);
-}
-
-
-RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
- Register temp_reg,
- int extra_slot_offset) {
- // cf. TemplateTable::prepare_invoke(), if (load_receiver).
- int stackElementSize = Interpreter::stackElementSize;
- int offset = extra_slot_offset * stackElementSize;
- if (arg_slot.is_constant()) {
- offset += arg_slot.as_constant() * stackElementSize;
- return offset;
- } else {
- assert(temp_reg != noreg, "must specify");
- sll_ptr(arg_slot.as_register(), exact_log2(stackElementSize), temp_reg);
- if (offset != 0)
- add(temp_reg, offset, temp_reg);
- return temp_reg;
- }
-}
-
-
-Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
- Register temp_reg,
- int extra_slot_offset) {
- return Address(Gargs, argument_offset(arg_slot, temp_reg, extra_slot_offset));
-}
-
-
-void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
- Register temp_reg,
- Label& done, Label* slow_case,
- BiasedLockingCounters* counters) {
- assert(UseBiasedLocking, "why call this otherwise?");
-
- if (PrintBiasedLockingStatistics) {
- assert_different_registers(obj_reg, mark_reg, temp_reg, O7);
- if (counters == NULL)
- counters = BiasedLocking::counters();
- }
-
- Label cas_label;
-
- // Biased locking
- // See whether the lock is currently biased toward our thread and
- // whether the epoch is still valid
- // Note that the runtime guarantees sufficient alignment of JavaThread
- // pointers to allow age to be placed into low bits
- assert(markWord::age_shift == markWord::lock_bits + markWord::biased_lock_bits, "biased locking makes assumptions about bit layout");
- and3(mark_reg, markWord::biased_lock_mask_in_place, temp_reg);
- cmp_and_brx_short(temp_reg, markWord::biased_lock_pattern, Assembler::notEqual, Assembler::pn, cas_label);
-
- load_klass(obj_reg, temp_reg);
- ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
- or3(G2_thread, temp_reg, temp_reg);
- xor3(mark_reg, temp_reg, temp_reg);
- andcc(temp_reg, ~((int) markWord::age_mask_in_place), temp_reg);
- if (counters != NULL) {
- cond_inc(Assembler::equal, (address) counters->biased_lock_entry_count_addr(), mark_reg, temp_reg);
- // Reload mark_reg as we may need it later
- ld_ptr(Address(obj_reg, oopDesc::mark_offset_in_bytes()), mark_reg);
- }
- brx(Assembler::equal, true, Assembler::pt, done);
- delayed()->nop();
-
- Label try_revoke_bias;
- Label try_rebias;
- Address mark_addr = Address(obj_reg, oopDesc::mark_offset_in_bytes());
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
-
- // At this point we know that the header has the bias pattern and
- // that we are not the bias owner in the current epoch. We need to
- // figure out more details about the state of the header in order to
- // know what operations can be legally performed on the object's
- // header.
-
- // If the low three bits in the xor result aren't clear, that means
- // the prototype header is no longer biased and we have to revoke
- // the bias on this object.
- btst(markWord::biased_lock_mask_in_place, temp_reg);
- brx(Assembler::notZero, false, Assembler::pn, try_revoke_bias);
-
- // Biasing is still enabled for this data type. See whether the
- // epoch of the current bias is still valid, meaning that the epoch
- // bits of the mark word are equal to the epoch bits of the
- // prototype header. (Note that the prototype header's epoch bits
- // only change at a safepoint.) If not, attempt to rebias the object
- // toward the current thread. Note that we must be absolutely sure
- // that the current epoch is invalid in order to do this because
- // otherwise the manipulations it performs on the mark word are
- // illegal.
- delayed()->btst(markWord::epoch_mask_in_place, temp_reg);
- brx(Assembler::notZero, false, Assembler::pn, try_rebias);
-
- // The epoch of the current bias is still valid but we know nothing
- // about the owner; it might be set or it might be clear. Try to
- // acquire the bias of the object using an atomic operation. If this
- // fails we will go in to the runtime to revoke the object's bias.
- // Note that we first construct the presumed unbiased header so we
- // don't accidentally blow away another thread's valid bias.
- delayed()->and3(mark_reg,
- markWord::biased_lock_mask_in_place | markWord::age_mask_in_place | markWord::epoch_mask_in_place,
- mark_reg);
- or3(G2_thread, mark_reg, temp_reg);
- cas_ptr(mark_addr.base(), mark_reg, temp_reg);
- // If the biasing toward our thread failed, this means that
- // another thread succeeded in biasing it toward itself and we
- // need to revoke that bias. The revocation will occur in the
- // interpreter runtime in the slow case.
- cmp(mark_reg, temp_reg);
- if (counters != NULL) {
- cond_inc(Assembler::zero, (address) counters->anonymously_biased_lock_entry_count_addr(), mark_reg, temp_reg);
- }
- if (slow_case != NULL) {
- brx(Assembler::notEqual, true, Assembler::pn, *slow_case);
- delayed()->nop();
- }
- ba_short(done);
-
- bind(try_rebias);
- // At this point we know the epoch has expired, meaning that the
- // current "bias owner", if any, is actually invalid. Under these
- // circumstances _only_, we are allowed to use the current header's
- // value as the comparison value when doing the cas to acquire the
- // bias in the current epoch. In other words, we allow transfer of
- // the bias from one thread to another directly in this situation.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- load_klass(obj_reg, temp_reg);
- ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
- or3(G2_thread, temp_reg, temp_reg);
- cas_ptr(mark_addr.base(), mark_reg, temp_reg);
- // If the biasing toward our thread failed, this means that
- // another thread succeeded in biasing it toward itself and we
- // need to revoke that bias. The revocation will occur in the
- // interpreter runtime in the slow case.
- cmp(mark_reg, temp_reg);
- if (counters != NULL) {
- cond_inc(Assembler::zero, (address) counters->rebiased_lock_entry_count_addr(), mark_reg, temp_reg);
- }
- if (slow_case != NULL) {
- brx(Assembler::notEqual, true, Assembler::pn, *slow_case);
- delayed()->nop();
- }
- ba_short(done);
-
- bind(try_revoke_bias);
- // The prototype mark in the klass doesn't have the bias bit set any
- // more, indicating that objects of this data type are not supposed
- // to be biased any more. We are going to try to reset the mark of
- // this object to the prototype value and fall through to the
- // CAS-based locking scheme. Note that if our CAS fails, it means
- // that another thread raced us for the privilege of revoking the
- // bias of this particular object, so it's okay to continue in the
- // normal locking code.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- load_klass(obj_reg, temp_reg);
- ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
- cas_ptr(mark_addr.base(), mark_reg, temp_reg);
- // Fall through to the normal CAS-based lock, because no matter what
- // the result of the above CAS, some thread must have succeeded in
- // removing the bias bit from the object's header.
- if (counters != NULL) {
- cmp(mark_reg, temp_reg);
- cond_inc(Assembler::zero, (address) counters->revoked_lock_entry_count_addr(), mark_reg, temp_reg);
- }
-
- bind(cas_label);
-}
-
-void MacroAssembler::biased_locking_exit (Address mark_addr, Register temp_reg, Label& done,
- bool allow_delay_slot_filling) {
- // Check for biased locking unlock case, which is a no-op
- // Note: we do not have to check the thread ID for two reasons.
- // First, the interpreter checks for IllegalMonitorStateException at
- // a higher level. Second, if the bias was revoked while we held the
- // lock, the object could not be rebiased toward another thread, so
- // the bias bit would be clear.
- ld_ptr(mark_addr, temp_reg);
- and3(temp_reg, markWord::biased_lock_mask_in_place, temp_reg);
- cmp(temp_reg, markWord::biased_lock_pattern);
- brx(Assembler::equal, allow_delay_slot_filling, Assembler::pt, done);
- delayed();
- if (!allow_delay_slot_filling) {
- nop();
- }
-}
-
-
-// compiler_lock_object() and compiler_unlock_object() are direct transliterations
-// of i486.ad fast_lock() and fast_unlock(). See those methods for detailed comments.
-// The code could be tightened up considerably.
-//
-// box->dhw disposition - post-conditions at DONE_LABEL.
-// - Successful inflated lock: box->dhw != 0.
-// Any non-zero value suffices.
-// Consider G2_thread, rsp, boxReg, or markWord::unused_mark()
-// - Successful Stack-lock: box->dhw == mark.
-// box->dhw must contain the displaced mark word value
-// - Failure -- icc.ZFlag == 0 and box->dhw is undefined.
-// The slow-path enter() is responsible for setting
-// box->dhw = NonZero (typically markWord::unused_mark()).
-// - Biased: box->dhw is undefined
-//
-// SPARC refworkload performance - specifically jetstream and scimark - are
-// extremely sensitive to the size of the code emitted by compiler_lock_object
-// and compiler_unlock_object. Critically, the key factor is code size, not path
-// length. (Simply experiments to pad CLO with unexecuted NOPs demonstrte the
-// effect).
-
-
-void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark,
- Register Rbox, Register Rscratch,
- BiasedLockingCounters* counters,
- bool try_bias) {
- Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
-
- verify_oop(Roop);
- Label done ;
-
- if (counters != NULL) {
- inc_counter((address) counters->total_entry_count_addr(), Rmark, Rscratch);
- }
-
- // Aggressively avoid the Store-before-CAS penalty
- // Defer the store into box->dhw until after the CAS
- Label IsInflated, Recursive ;
-
-// Anticipate CAS -- Avoid RTS->RTO upgrade
-// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
-
- ld_ptr(mark_addr, Rmark); // fetch obj->mark
- // Triage: biased, stack-locked, neutral, inflated
-
- if (try_bias) {
- biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
- // Invariant: if control reaches this point in the emitted stream
- // then Rmark has not been modified.
- }
- andcc(Rmark, 2, G0);
- brx(Assembler::notZero, false, Assembler::pn, IsInflated);
- delayed()-> // Beware - dangling delay-slot
-
- // Try stack-lock acquisition.
- // Transiently install BUSY (0) encoding in the mark word.
- // if the CAS of 0 into the mark was successful then we execute:
- // ST box->dhw = mark -- save fetched mark in on-stack basiclock box
- // ST obj->mark = box -- overwrite transient 0 value
- // This presumes TSO, of course.
-
- mov(0, Rscratch);
- or3(Rmark, markWord::unlocked_value, Rmark);
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- cas_ptr(mark_addr.base(), Rmark, Rscratch);
-// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
- cmp(Rscratch, Rmark);
- brx(Assembler::notZero, false, Assembler::pn, Recursive);
- delayed()->st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
- if (counters != NULL) {
- cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch);
- }
- ba(done);
- delayed()->st_ptr(Rbox, mark_addr);
-
- bind(Recursive);
- // Stack-lock attempt failed - check for recursive stack-lock.
- // Tests show that we can remove the recursive case with no impact
- // on refworkload 0.83. If we need to reduce the size of the code
- // emitted by compiler_lock_object() the recursive case is perfect
- // candidate.
- //
- // A more extreme idea is to always inflate on stack-lock recursion.
- // This lets us eliminate the recursive checks in compiler_lock_object
- // and compiler_unlock_object and the (box->dhw == 0) encoding.
- // A brief experiment - requiring changes to synchronizer.cpp, interpreter,
- // and showed a performance *increase*. In the same experiment I eliminated
- // the fast-path stack-lock code from the interpreter and always passed
- // control to the "slow" operators in synchronizer.cpp.
-
- // RScratch contains the fetched obj->mark value from the failed CAS.
- sub(Rscratch, STACK_BIAS, Rscratch);
- sub(Rscratch, SP, Rscratch);
- assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
- andcc(Rscratch, 0xfffff003, Rscratch);
- if (counters != NULL) {
- // Accounting needs the Rscratch register
- st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
- cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch);
- ba_short(done);
- } else {
- ba(done);
- delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
- }
-
- bind (IsInflated);
-
- // Try to CAS m->owner from null to Self
- // Invariant: if we acquire the lock then _recursions should be 0.
- add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
- mov(G2_thread, Rscratch);
- cas_ptr(Rmark, G0, Rscratch);
- andcc(Rscratch, Rscratch, G0); // set ICCs for done: icc.zf iff success
- // set icc.zf : 1=success 0=failure
- // ST box->displaced_header = NonZero.
- // Any non-zero value suffices:
- // markWord::unused_mark(), G2_thread, RBox, RScratch, rsp, etc.
- st_ptr(Rbox, Rbox, BasicLock::displaced_header_offset_in_bytes());
- // Intentional fall-through into done
-
- bind (done);
-}
-
-void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark,
- Register Rbox, Register Rscratch,
- bool try_bias) {
- Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
-
- Label done ;
-
- // Beware ... If the aggregate size of the code emitted by CLO and CUO is
- // is too large performance rolls abruptly off a cliff.
- // This could be related to inlining policies, code cache management, or
- // I$ effects.
- Label LStacked ;
-
- if (try_bias) {
- // TODO: eliminate redundant LDs of obj->mark
- biased_locking_exit(mark_addr, Rscratch, done);
- }
-
- ld_ptr(Roop, oopDesc::mark_offset_in_bytes(), Rmark);
- ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rscratch);
- andcc(Rscratch, Rscratch, G0);
- brx(Assembler::zero, false, Assembler::pn, done);
- delayed()->nop(); // consider: relocate fetch of mark, above, into this DS
- andcc(Rmark, 2, G0);
- brx(Assembler::zero, false, Assembler::pt, LStacked);
- delayed()->nop();
-
- // It's inflated
- // Conceptually we need a #loadstore|#storestore "release" MEMBAR before
- // the ST of 0 into _owner which releases the lock. This prevents loads
- // and stores within the critical section from reordering (floating)
- // past the store that releases the lock. But TSO is a strong memory model
- // and that particular flavor of barrier is a noop, so we can safely elide it.
- // Note that we use 1-0 locking by default for the inflated case. We
- // close the resultant (and rare) race by having contended threads in
- // monitorenter periodically poll _owner.
-
- // 1-0 form : avoids CAS and MEMBAR in the common case
- // Do not bother to ratify that m->Owner == Self.
- ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), Rbox);
- orcc(Rbox, G0, G0);
- brx(Assembler::notZero, false, Assembler::pn, done);
- delayed()->
- ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)), Rscratch);
- ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)), Rbox);
- orcc(Rbox, Rscratch, G0);
- brx(Assembler::zero, false, Assembler::pt, done);
- delayed()->
- st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
-
- membar(StoreLoad);
- // Check that _succ is (or remains) non-zero
- ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch);
- andcc(Rscratch, Rscratch, G0);
- brx(Assembler::notZero, false, Assembler::pt, done);
- delayed()->andcc(G0, G0, G0);
- add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
- mov(G2_thread, Rscratch);
- cas_ptr(Rmark, G0, Rscratch);
- cmp(Rscratch, G0);
- // invert icc.zf and goto done
- // A slightly better v8+/v9 idiom would be the following:
- // movrnz Rscratch,1,Rscratch
- // ba done
- // xorcc Rscratch,1,G0
- // In v8+ mode the idiom would be valid IFF Rscratch was a G or O register
- brx(Assembler::notZero, false, Assembler::pt, done);
- delayed()->cmp(G0, G0);
- br(Assembler::always, false, Assembler::pt, done);
- delayed()->cmp(G0, 1);
-
- bind (LStacked);
- // Consider: we could replace the expensive CAS in the exit
- // path with a simple ST of the displaced mark value fetched from
- // the on-stack basiclock box. That admits a race where a thread T2
- // in the slow lock path -- inflating with monitor M -- could race a
- // thread T1 in the fast unlock path, resulting in a missed wakeup for T2.
- // More precisely T1 in the stack-lock unlock path could "stomp" the
- // inflated mark value M installed by T2, resulting in an orphan
- // object monitor M and T2 becoming stranded. We can remedy that situation
- // by having T2 periodically poll the object's mark word using timed wait
- // operations. If T2 discovers that a stomp has occurred it vacates
- // the monitor M and wakes any other threads stranded on the now-orphan M.
- // In addition the monitor scavenger, which performs deflation,
- // would also need to check for orpan monitors and stranded threads.
- //
- // Finally, inflation is also used when T2 needs to assign a hashCode
- // to O and O is stack-locked by T1. The "stomp" race could cause
- // an assigned hashCode value to be lost. We can avoid that condition
- // and provide the necessary hashCode stability invariants by ensuring
- // that hashCode generation is idempotent between copying GCs.
- // For example we could compute the hashCode of an object O as
- // O's heap address XOR some high quality RNG value that is refreshed
- // at GC-time. The monitor scavenger would install the hashCode
- // found in any orphan monitors. Again, the mechanism admits a
- // lost-update "stomp" WAW race but detects and recovers as needed.
- //
- // A prototype implementation showed excellent results, although
- // the scavenger and timeout code was rather involved.
-
- cas_ptr(mark_addr.base(), Rbox, Rscratch);
- cmp(Rbox, Rscratch);
- // Intentional fall through into done ...
-
- bind(done);
-}
-
-void MacroAssembler::verify_tlab() {
-#ifdef ASSERT
- if (UseTLAB && VerifyOops) {
- Label next, next2, ok;
- Register t1 = L0;
- Register t2 = L1;
- Register t3 = L2;
-
- save_frame(0);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t2);
- or3(t1, t2, t3);
- cmp_and_br_short(t1, t2, Assembler::greaterEqual, Assembler::pn, next);
- STOP("assert(top >= start)");
- should_not_reach_here();
-
- bind(next);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), t2);
- or3(t3, t2, t3);
- cmp_and_br_short(t1, t2, Assembler::lessEqual, Assembler::pn, next2);
- STOP("assert(top <= end)");
- should_not_reach_here();
-
- bind(next2);
- and3(t3, MinObjAlignmentInBytesMask, t3);
- cmp_and_br_short(t3, 0, Assembler::lessEqual, Assembler::pn, ok);
- STOP("assert(aligned)");
- should_not_reach_here();
-
- bind(ok);
- restore();
- }
-#endif
-}
-
-
-void MacroAssembler::eden_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- Label& slow_case // continuation point if fast allocation fails
-){
- // make sure arguments make sense
- assert_different_registers(obj, var_size_in_bytes, t1, t2);
- assert(0 <= con_size_in_bytes && Assembler::is_simm13(con_size_in_bytes), "illegal object size");
- assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
-
- if (!Universe::heap()->supports_inline_contig_alloc()) {
- // No allocation in the shared eden.
- ba(slow_case);
- delayed()->nop();
- } else {
- // get eden boundaries
- // note: we need both top & top_addr!
- const Register top_addr = t1;
- const Register end = t2;
-
- CollectedHeap* ch = Universe::heap();
- set((intx)ch->top_addr(), top_addr);
- intx delta = (intx)ch->end_addr() - (intx)ch->top_addr();
- ld_ptr(top_addr, delta, end);
- ld_ptr(top_addr, 0, obj);
-
- // try to allocate
- Label retry;
- bind(retry);
-#ifdef ASSERT
- // make sure eden top is properly aligned
- {
- Label L;
- btst(MinObjAlignmentInBytesMask, obj);
- br(Assembler::zero, false, Assembler::pt, L);
- delayed()->nop();
- STOP("eden top is not properly aligned");
- bind(L);
- }
-#endif // ASSERT
- const Register free = end;
- sub(end, obj, free); // compute amount of free space
- if (var_size_in_bytes->is_valid()) {
- // size is unknown at compile time
- cmp(free, var_size_in_bytes);
- brx(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case
- delayed()->add(obj, var_size_in_bytes, end);
- } else {
- // size is known at compile time
- cmp(free, con_size_in_bytes);
- brx(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case
- delayed()->add(obj, con_size_in_bytes, end);
- }
- // Compare obj with the value at top_addr; if still equal, swap the value of
- // end with the value at top_addr. If not equal, read the value at top_addr
- // into end.
- cas_ptr(top_addr, obj, end);
- // if someone beat us on the allocation, try again, otherwise continue
- cmp(obj, end);
- brx(Assembler::notEqual, false, Assembler::pn, retry);
- delayed()->mov(end, obj); // nop if successfull since obj == end
-
-#ifdef ASSERT
- // make sure eden top is properly aligned
- {
- Label L;
- const Register top_addr = t1;
-
- set((intx)ch->top_addr(), top_addr);
- ld_ptr(top_addr, 0, top_addr);
- btst(MinObjAlignmentInBytesMask, top_addr);
- br(Assembler::zero, false, Assembler::pt, L);
- delayed()->nop();
- STOP("eden top is not properly aligned");
- bind(L);
- }
-#endif // ASSERT
- }
-}
-
-
-void MacroAssembler::tlab_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Label& slow_case // continuation point if fast allocation fails
-){
- // make sure arguments make sense
- assert_different_registers(obj, var_size_in_bytes, t1);
- assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size");
- assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
-
- const Register free = t1;
-
- verify_tlab();
-
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), obj);
-
- // calculate amount of free space
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), free);
- sub(free, obj, free);
-
- Label done;
- if (var_size_in_bytes == noreg) {
- cmp(free, con_size_in_bytes);
- } else {
- cmp(free, var_size_in_bytes);
- }
- br(Assembler::less, false, Assembler::pn, slow_case);
- // calculate the new top pointer
- if (var_size_in_bytes == noreg) {
- delayed()->add(obj, con_size_in_bytes, free);
- } else {
- delayed()->add(obj, var_size_in_bytes, free);
- }
-
- bind(done);
-
-#ifdef ASSERT
- // make sure new free pointer is properly aligned
- {
- Label L;
- btst(MinObjAlignmentInBytesMask, free);
- br(Assembler::zero, false, Assembler::pt, L);
- delayed()->nop();
- STOP("updated TLAB free is not properly aligned");
- bind(L);
- }
-#endif // ASSERT
-
- // update the tlab top pointer
- st_ptr(free, G2_thread, in_bytes(JavaThread::tlab_top_offset()));
- verify_tlab();
-}
-
-void MacroAssembler::zero_memory(Register base, Register index) {
- assert_different_registers(base, index);
- Label loop;
- bind(loop);
- subcc(index, HeapWordSize, index);
- brx(Assembler::greaterEqual, true, Assembler::pt, loop);
- delayed()->st_ptr(G0, base, index);
-}
-
-void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes,
- Register t1, Register t2) {
- // Bump total bytes allocated by this thread
- assert(t1->is_global(), "must be global reg"); // so all 64 bits are saved on a context switch
- assert_different_registers(size_in_bytes.register_or_noreg(), t1, t2);
- // v8 support has gone the way of the dodo
- ldx(G2_thread, in_bytes(JavaThread::allocated_bytes_offset()), t1);
- add(t1, ensure_simm13_or_reg(size_in_bytes, t2), t1);
- stx(t1, G2_thread, in_bytes(JavaThread::allocated_bytes_offset()));
-}
-
-Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) {
- switch (cond) {
- // Note some conditions are synonyms for others
- case Assembler::never: return Assembler::always;
- case Assembler::zero: return Assembler::notZero;
- case Assembler::lessEqual: return Assembler::greater;
- case Assembler::less: return Assembler::greaterEqual;
- case Assembler::lessEqualUnsigned: return Assembler::greaterUnsigned;
- case Assembler::lessUnsigned: return Assembler::greaterEqualUnsigned;
- case Assembler::negative: return Assembler::positive;
- case Assembler::overflowSet: return Assembler::overflowClear;
- case Assembler::always: return Assembler::never;
- case Assembler::notZero: return Assembler::zero;
- case Assembler::greater: return Assembler::lessEqual;
- case Assembler::greaterEqual: return Assembler::less;
- case Assembler::greaterUnsigned: return Assembler::lessEqualUnsigned;
- case Assembler::greaterEqualUnsigned: return Assembler::lessUnsigned;
- case Assembler::positive: return Assembler::negative;
- case Assembler::overflowClear: return Assembler::overflowSet;
- }
-
- ShouldNotReachHere(); return Assembler::overflowClear;
-}
-
-void MacroAssembler::cond_inc(Assembler::Condition cond, address counter_ptr,
- Register Rtmp1, Register Rtmp2 /*, Register Rtmp3, Register Rtmp4 */) {
- Condition negated_cond = negate_condition(cond);
- Label L;
- brx(negated_cond, false, Assembler::pt, L);
- delayed()->nop();
- inc_counter(counter_ptr, Rtmp1, Rtmp2);
- bind(L);
-}
-
-void MacroAssembler::inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2) {
- AddressLiteral addrlit(counter_addr);
- sethi(addrlit, Rtmp1); // Move hi22 bits into temporary register.
- Address addr(Rtmp1, addrlit.low10()); // Build an address with low10 bits.
- ld(addr, Rtmp2);
- inc(Rtmp2);
- st(Rtmp2, addr);
-}
-
-void MacroAssembler::inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2) {
- inc_counter((address) counter_addr, Rtmp1, Rtmp2);
-}
-
-SkipIfEqual::SkipIfEqual(
- MacroAssembler* masm, Register temp, const bool* flag_addr,
- Assembler::Condition condition) {
- _masm = masm;
- AddressLiteral flag(flag_addr);
- _masm->sethi(flag, temp);
- _masm->ldub(temp, flag.low10(), temp);
- _masm->tst(temp);
- _masm->br(condition, false, Assembler::pt, _label);
- _masm->delayed()->nop();
-}
-
-SkipIfEqual::~SkipIfEqual() {
- _masm->bind(_label);
-}
-
-void MacroAssembler::bang_stack_with_offset(int offset) {
- // stack grows down, caller passes positive offset
- assert(offset > 0, "must bang with negative offset");
- set((-offset)+STACK_BIAS, G3_scratch);
- st(G0, SP, G3_scratch);
-}
-
-// Writes to stack successive pages until offset reached to check for
-// stack overflow + shadow pages. This clobbers tsp and scratch.
-void MacroAssembler::bang_stack_size(Register Rsize, Register Rtsp,
- Register Rscratch) {
- // Use stack pointer in temp stack pointer
- mov(SP, Rtsp);
-
- // Bang stack for total size given plus stack shadow page size.
- // Bang one page at a time because a large size can overflow yellow and
- // red zones (the bang will fail but stack overflow handling can't tell that
- // it was a stack overflow bang vs a regular segv).
- int offset = os::vm_page_size();
- Register Roffset = Rscratch;
-
- Label loop;
- bind(loop);
- set((-offset)+STACK_BIAS, Rscratch);
- st(G0, Rtsp, Rscratch);
- set(offset, Roffset);
- sub(Rsize, Roffset, Rsize);
- cmp(Rsize, G0);
- br(Assembler::greater, false, Assembler::pn, loop);
- delayed()->sub(Rtsp, Roffset, Rtsp);
-
- // Bang down shadow pages too.
- // At this point, (tmp-0) is the last address touched, so don't
- // touch it again. (It was touched as (tmp-pagesize) but then tmp
- // was post-decremented.) Skip this address by starting at i=1, and
- // touch a few more pages below. N.B. It is important to touch all
- // the way down to and including i=StackShadowPages.
- for (int i = 1; i < JavaThread::stack_shadow_zone_size() / os::vm_page_size(); i++) {
- set((-i*offset)+STACK_BIAS, Rscratch);
- st(G0, Rtsp, Rscratch);
- }
-}
-
-void MacroAssembler::reserved_stack_check() {
- // testing if reserved zone needs to be enabled
- Label no_reserved_zone_enabling;
-
- ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G4_scratch);
- cmp_and_brx_short(SP, G4_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling);
-
- call_VM_leaf(L0, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread);
-
- AddressLiteral stub(StubRoutines::throw_delayed_StackOverflowError_entry());
- jump_to(stub, G4_scratch);
- delayed()->restore();
-
- should_not_reach_here();
-
- bind(no_reserved_zone_enabling);
-}
-// ((OopHandle)result).resolve();
-void MacroAssembler::resolve_oop_handle(Register result, Register tmp) {
- // OopHandle::resolve is an indirection.
- access_load_at(T_OBJECT, IN_NATIVE, Address(result, 0), result, tmp);
-}
-
-void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) {
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- ld_ptr(method, in_bytes(Method::const_offset()), mirror);
- ld_ptr(mirror, in_bytes(ConstMethod::constants_offset()), mirror);
- ld_ptr(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror);
- ld_ptr(mirror, mirror_offset, mirror);
- resolve_oop_handle(mirror, tmp);
-}
-
-void MacroAssembler::load_klass(Register src_oop, Register klass) {
- // The number of bytes in this code is used by
- // MachCallDynamicJavaNode::ret_addr_offset()
- // if this changes, change that.
- if (UseCompressedClassPointers) {
- lduw(src_oop, oopDesc::klass_offset_in_bytes(), klass);
- decode_klass_not_null(klass);
- } else {
- ld_ptr(src_oop, oopDesc::klass_offset_in_bytes(), klass);
- }
-}
-
-void MacroAssembler::store_klass(Register klass, Register dst_oop) {
- if (UseCompressedClassPointers) {
- assert(dst_oop != klass, "not enough registers");
- encode_klass_not_null(klass);
- st(klass, dst_oop, oopDesc::klass_offset_in_bytes());
- } else {
- st_ptr(klass, dst_oop, oopDesc::klass_offset_in_bytes());
- }
-}
-
-void MacroAssembler::store_klass_gap(Register s, Register d) {
- if (UseCompressedClassPointers) {
- assert(s != d, "not enough registers");
- st(s, d, oopDesc::klass_gap_offset_in_bytes());
- }
-}
-
-void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
- Register src, Address dst, Register tmp) {
- BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
- bool as_raw = (decorators & AS_RAW) != 0;
- if (as_raw) {
- bs->BarrierSetAssembler::store_at(this, decorators, type, src, dst, tmp);
- } else {
- bs->store_at(this, decorators, type, src, dst, tmp);
- }
-}
-
-void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
- Address src, Register dst, Register tmp) {
- BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- decorators = AccessInternal::decorator_fixup(decorators);
- bool as_raw = (decorators & AS_RAW) != 0;
- if (as_raw) {
- bs->BarrierSetAssembler::load_at(this, decorators, type, src, dst, tmp);
- } else {
- bs->load_at(this, decorators, type, src, dst, tmp);
- }
-}
-
-void MacroAssembler::load_heap_oop(const Address& s, Register d, Register tmp, DecoratorSet decorators) {
- access_load_at(T_OBJECT, IN_HEAP | decorators, s, d, tmp);
-}
-
-void MacroAssembler::load_heap_oop(Register s1, Register s2, Register d, Register tmp, DecoratorSet decorators) {
- access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2), d, tmp);
-}
-
-void MacroAssembler::load_heap_oop(Register s1, int simm13a, Register d, Register tmp, DecoratorSet decorators) {
- access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, simm13a), d, tmp);
-}
-
-void MacroAssembler::load_heap_oop(Register s1, RegisterOrConstant s2, Register d, Register tmp, DecoratorSet decorators) {
- if (s2.is_constant()) {
- access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2.as_constant()), d, tmp);
- } else {
- access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2.as_register()), d, tmp);
- }
-}
-
-void MacroAssembler::store_heap_oop(Register d, Register s1, Register s2, Register tmp, DecoratorSet decorators) {
- access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(s1, s2), tmp);
-}
-
-void MacroAssembler::store_heap_oop(Register d, Register s1, int simm13a, Register tmp, DecoratorSet decorators) {
- access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(s1, simm13a), tmp);
-}
-
-void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset, Register tmp, DecoratorSet decorators) {
- if (a.has_index()) {
- assert(!a.has_disp(), "not supported yet");
- assert(offset == 0, "not supported yet");
- access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(a.base(), a.index()), tmp);
- } else {
- access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(a.base(), a.disp() + offset), tmp);
- }
-}
-
-
-void MacroAssembler::encode_heap_oop(Register src, Register dst) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong");
- verify_oop(src);
- if (CompressedOops::base() == NULL) {
- srlx(src, LogMinObjAlignmentInBytes, dst);
- return;
- }
- Label done;
- if (src == dst) {
- // optimize for frequent case src == dst
- bpr(rc_nz, true, Assembler::pt, src, done);
- delayed() -> sub(src, G6_heapbase, dst); // annuled if not taken
- bind(done);
- srlx(src, LogMinObjAlignmentInBytes, dst);
- } else {
- bpr(rc_z, false, Assembler::pn, src, done);
- delayed() -> mov(G0, dst);
- // could be moved before branch, and annulate delay,
- // but may add some unneeded work decoding null
- sub(src, G6_heapbase, dst);
- srlx(dst, LogMinObjAlignmentInBytes, dst);
- bind(done);
- }
-}
-
-
-void MacroAssembler::encode_heap_oop_not_null(Register r) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong");
- verify_oop(r);
- if (CompressedOops::base() != NULL)
- sub(r, G6_heapbase, r);
- srlx(r, LogMinObjAlignmentInBytes, r);
-}
-
-void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong");
- verify_oop(src);
- if (CompressedOops::base() == NULL) {
- srlx(src, LogMinObjAlignmentInBytes, dst);
- } else {
- sub(src, G6_heapbase, dst);
- srlx(dst, LogMinObjAlignmentInBytes, dst);
- }
-}
-
-// Same algorithm as oops.inline.hpp decode_heap_oop.
-void MacroAssembler::decode_heap_oop(Register src, Register dst) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong");
- sllx(src, LogMinObjAlignmentInBytes, dst);
- if (CompressedOops::base() != NULL) {
- Label done;
- bpr(rc_nz, true, Assembler::pt, dst, done);
- delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken
- bind(done);
- }
- verify_oop(dst);
-}
-
-void MacroAssembler::decode_heap_oop_not_null(Register r) {
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong");
- sllx(r, LogMinObjAlignmentInBytes, r);
- if (CompressedOops::base() != NULL)
- add(r, G6_heapbase, r);
-}
-
-void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) {
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- assert (UseCompressedOops, "must be compressed");
- assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong");
- sllx(src, LogMinObjAlignmentInBytes, dst);
- if (CompressedOops::base() != NULL)
- add(dst, G6_heapbase, dst);
-}
-
-void MacroAssembler::encode_klass_not_null(Register r) {
- assert (UseCompressedClassPointers, "must be compressed");
- if (CompressedKlassPointers::base() != NULL) {
- assert(r != G6_heapbase, "bad register choice");
- set((intptr_t)CompressedKlassPointers::base(), G6_heapbase);
- sub(r, G6_heapbase, r);
- if (CompressedKlassPointers::shift() != 0) {
- assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift(), "decode alg wrong");
- srlx(r, LogKlassAlignmentInBytes, r);
- }
- reinit_heapbase();
- } else {
- assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong");
- srlx(r, CompressedKlassPointers::shift(), r);
- }
-}
-
-void MacroAssembler::encode_klass_not_null(Register src, Register dst) {
- if (src == dst) {
- encode_klass_not_null(src);
- } else {
- assert (UseCompressedClassPointers, "must be compressed");
- if (CompressedKlassPointers::base() != NULL) {
- set((intptr_t)CompressedKlassPointers::base(), dst);
- sub(src, dst, dst);
- if (CompressedKlassPointers::shift() != 0) {
- srlx(dst, LogKlassAlignmentInBytes, dst);
- }
- } else {
- // shift src into dst
- assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong");
- srlx(src, CompressedKlassPointers::shift(), dst);
- }
- }
-}
-
-// Function instr_size_for_decode_klass_not_null() counts the instructions
-// generated by decode_klass_not_null() and reinit_heapbase(). Hence, if
-// the instructions they generate change, then this method needs to be updated.
-int MacroAssembler::instr_size_for_decode_klass_not_null() {
- assert (UseCompressedClassPointers, "only for compressed klass ptrs");
- int num_instrs = 1; // shift src,dst or add
- if (CompressedKlassPointers::base() != NULL) {
- // set + add + set
- num_instrs += insts_for_internal_set((intptr_t)CompressedKlassPointers::base()) +
- insts_for_internal_set((intptr_t)CompressedOops::ptrs_base());
- if (CompressedKlassPointers::shift() != 0) {
- num_instrs += 1; // sllx
- }
- }
- return num_instrs * BytesPerInstWord;
-}
-
-// !!! If the instructions that get generated here change then function
-// instr_size_for_decode_klass_not_null() needs to get updated.
-void MacroAssembler::decode_klass_not_null(Register r) {
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- assert (UseCompressedClassPointers, "must be compressed");
- if (CompressedKlassPointers::base() != NULL) {
- assert(r != G6_heapbase, "bad register choice");
- set((intptr_t)CompressedKlassPointers::base(), G6_heapbase);
- if (CompressedKlassPointers::shift() != 0)
- sllx(r, LogKlassAlignmentInBytes, r);
- add(r, G6_heapbase, r);
- reinit_heapbase();
- } else {
- assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong");
- sllx(r, CompressedKlassPointers::shift(), r);
- }
-}
-
-void MacroAssembler::decode_klass_not_null(Register src, Register dst) {
- if (src == dst) {
- decode_klass_not_null(src);
- } else {
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- assert (UseCompressedClassPointers, "must be compressed");
- if (CompressedKlassPointers::base() != NULL) {
- if (CompressedKlassPointers::shift() != 0) {
- assert((src != G6_heapbase) && (dst != G6_heapbase), "bad register choice");
- set((intptr_t)CompressedKlassPointers::base(), G6_heapbase);
- sllx(src, LogKlassAlignmentInBytes, dst);
- add(dst, G6_heapbase, dst);
- reinit_heapbase();
- } else {
- set((intptr_t)CompressedKlassPointers::base(), dst);
- add(src, dst, dst);
- }
- } else {
- // shift/mov src into dst.
- assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong");
- sllx(src, CompressedKlassPointers::shift(), dst);
- }
- }
-}
-
-void MacroAssembler::reinit_heapbase() {
- if (UseCompressedOops || UseCompressedClassPointers) {
- if (Universe::heap() != NULL) {
- set((intptr_t)CompressedOops::ptrs_base(), G6_heapbase);
- } else {
- AddressLiteral base(CompressedOops::ptrs_base_addr());
- load_ptr_contents(base, G6_heapbase);
- }
- }
-}
-
-// Use BIS for zeroing (count is in bytes).
-void MacroAssembler::bis_zeroing(Register to, Register count, Register temp, Label& Ldone) {
- assert(UseBlockZeroing && VM_Version::has_blk_zeroing(), "only works with BIS zeroing");
- Register end = count;
- int cache_line_size = VM_Version::prefetch_data_size();
- assert(cache_line_size > 0, "cache line size should be known for this code");
- // Minimum count when BIS zeroing can be used since
- // it needs membar which is expensive.
- int block_zero_size = MAX2(cache_line_size*3, (int)BlockZeroingLowLimit);
-
- Label small_loop;
- // Check if count is negative (dead code) or zero.
- // Note, count uses 64bit in 64 bit VM.
- cmp_and_brx_short(count, 0, Assembler::lessEqual, Assembler::pn, Ldone);
-
- // Use BIS zeroing only for big arrays since it requires membar.
- if (Assembler::is_simm13(block_zero_size)) { // < 4096
- cmp(count, block_zero_size);
- } else {
- set(block_zero_size, temp);
- cmp(count, temp);
- }
- br(Assembler::lessUnsigned, false, Assembler::pt, small_loop);
- delayed()->add(to, count, end);
-
- // Note: size is >= three (32 bytes) cache lines.
-
- // Clean the beginning of space up to next cache line.
- for (int offs = 0; offs < cache_line_size; offs += 8) {
- stx(G0, to, offs);
- }
-
- // align to next cache line
- add(to, cache_line_size, to);
- and3(to, -cache_line_size, to);
-
- // Note: size left >= two (32 bytes) cache lines.
-
- // BIS should not be used to zero tail (64 bytes)
- // to avoid zeroing a header of the following object.
- sub(end, (cache_line_size*2)-8, end);
-
- Label bis_loop;
- bind(bis_loop);
- stxa(G0, to, G0, Assembler::ASI_ST_BLKINIT_PRIMARY);
- add(to, cache_line_size, to);
- cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, bis_loop);
-
- // BIS needs membar.
- membar(Assembler::StoreLoad);
-
- add(end, (cache_line_size*2)-8, end); // restore end
- cmp_and_brx_short(to, end, Assembler::greaterEqualUnsigned, Assembler::pn, Ldone);
-
- // Clean the tail.
- bind(small_loop);
- stx(G0, to, 0);
- add(to, 8, to);
- cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, small_loop);
- nop(); // Separate short branches
-}
-
-/**
- * Update CRC-32[C] with a byte value according to constants in table
- *
- * @param [in,out]crc Register containing the crc.
- * @param [in]val Register containing the byte to fold into the CRC.
- * @param [in]table Register containing the table of crc constants.
- *
- * uint32_t crc;
- * val = crc_table[(val ^ crc) & 0xFF];
- * crc = val ^ (crc >> 8);
- */
-void MacroAssembler::update_byte_crc32(Register crc, Register val, Register table) {
- xor3(val, crc, val);
- and3(val, 0xFF, val);
- sllx(val, 2, val);
- lduw(table, val, val);
- srlx(crc, 8, crc);
- xor3(val, crc, crc);
-}
-
-// Reverse byte order of lower 32 bits, assuming upper 32 bits all zeros
-void MacroAssembler::reverse_bytes_32(Register src, Register dst, Register tmp) {
- srlx(src, 24, dst);
-
- sllx(src, 32+8, tmp);
- srlx(tmp, 32+24, tmp);
- sllx(tmp, 8, tmp);
- or3(dst, tmp, dst);
-
- sllx(src, 32+16, tmp);
- srlx(tmp, 32+24, tmp);
- sllx(tmp, 16, tmp);
- or3(dst, tmp, dst);
-
- sllx(src, 32+24, tmp);
- srlx(tmp, 32, tmp);
- or3(dst, tmp, dst);
-}
-
-void MacroAssembler::movitof_revbytes(Register src, FloatRegister dst, Register tmp1, Register tmp2) {
- reverse_bytes_32(src, tmp1, tmp2);
- movxtod(tmp1, dst);
-}
-
-void MacroAssembler::movftoi_revbytes(FloatRegister src, Register dst, Register tmp1, Register tmp2) {
- movdtox(src, tmp1);
- reverse_bytes_32(tmp1, dst, tmp2);
-}
-
-void MacroAssembler::fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register buf, int offset) {
- xmulx(xcrc_hi, xK_hi, xtmp_lo);
- xmulxhi(xcrc_hi, xK_hi, xtmp_hi);
- xmulxhi(xcrc_lo, xK_lo, xcrc_hi);
- xmulx(xcrc_lo, xK_lo, xcrc_lo);
- xor3(xcrc_lo, xtmp_lo, xcrc_lo);
- xor3(xcrc_hi, xtmp_hi, xcrc_hi);
- ldxl(buf, G0, xtmp_lo);
- inc(buf, 8);
- ldxl(buf, G0, xtmp_hi);
- inc(buf, 8);
- xor3(xcrc_lo, xtmp_lo, xcrc_lo);
- xor3(xcrc_hi, xtmp_hi, xcrc_hi);
-}
-
-void MacroAssembler::fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register xbuf_hi, Register xbuf_lo) {
- mov(xcrc_lo, xtmp_lo);
- mov(xcrc_hi, xtmp_hi);
- xmulx(xtmp_hi, xK_hi, xtmp_lo);
- xmulxhi(xtmp_hi, xK_hi, xtmp_hi);
- xmulxhi(xcrc_lo, xK_lo, xcrc_hi);
- xmulx(xcrc_lo, xK_lo, xcrc_lo);
- xor3(xcrc_lo, xbuf_lo, xcrc_lo);
- xor3(xcrc_hi, xbuf_hi, xcrc_hi);
- xor3(xcrc_lo, xtmp_lo, xcrc_lo);
- xor3(xcrc_hi, xtmp_hi, xcrc_hi);
-}
-
-void MacroAssembler::fold_8bit_crc32(Register xcrc, Register table, Register xtmp, Register tmp) {
- and3(xcrc, 0xFF, tmp);
- sllx(tmp, 2, tmp);
- lduw(table, tmp, xtmp);
- srlx(xcrc, 8, xcrc);
- xor3(xtmp, xcrc, xcrc);
-}
-
-void MacroAssembler::fold_8bit_crc32(Register crc, Register table, Register tmp) {
- and3(crc, 0xFF, tmp);
- srlx(crc, 8, crc);
- sllx(tmp, 2, tmp);
- lduw(table, tmp, tmp);
- xor3(tmp, crc, crc);
-}
-
-#define CRC32_TMP_REG_NUM 18
-
-#define CRC32_CONST_64 0x163cd6124
-#define CRC32_CONST_96 0x0ccaa009e
-#define CRC32_CONST_160 0x1751997d0
-#define CRC32_CONST_480 0x1c6e41596
-#define CRC32_CONST_544 0x154442bd4
-
-void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Register table) {
-
- Label L_cleanup_loop, L_cleanup_check, L_align_loop, L_align_check;
- Label L_main_loop_prologue;
- Label L_fold_512b, L_fold_512b_loop, L_fold_128b;
- Label L_fold_tail, L_fold_tail_loop;
- Label L_8byte_fold_check;
-
- const Register tmp[CRC32_TMP_REG_NUM] = {L0, L1, L2, L3, L4, L5, L6, G1, I0, I1, I2, I3, I4, I5, I7, O4, O5, G3};
-
- Register const_64 = tmp[CRC32_TMP_REG_NUM-1];
- Register const_96 = tmp[CRC32_TMP_REG_NUM-1];
- Register const_160 = tmp[CRC32_TMP_REG_NUM-2];
- Register const_480 = tmp[CRC32_TMP_REG_NUM-1];
- Register const_544 = tmp[CRC32_TMP_REG_NUM-2];
-
- set(ExternalAddress(StubRoutines::crc_table_addr()), table);
-
- not1(crc); // ~c
- clruwu(crc); // clear upper 32 bits of crc
-
- // Check if below cutoff, proceed directly to cleanup code
- mov(31, G4);
- cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_check);
-
- // Align buffer to 8 byte boundry
- mov(8, O5);
- and3(buf, 0x7, O4);
- sub(O5, O4, O5);
- and3(O5, 0x7, O5);
- sub(len, O5, len);
- ba(L_align_check);
- delayed()->nop();
-
- // Alignment loop, table look up method for up to 7 bytes
- bind(L_align_loop);
- ldub(buf, 0, O4);
- inc(buf);
- dec(O5);
- xor3(O4, crc, O4);
- and3(O4, 0xFF, O4);
- sllx(O4, 2, O4);
- lduw(table, O4, O4);
- srlx(crc, 8, crc);
- xor3(O4, crc, crc);
- bind(L_align_check);
- nop();
- cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pt, L_align_loop);
-
- // Aligned on 64-bit (8-byte) boundry at this point
- // Check if still above cutoff (31-bytes)
- mov(31, G4);
- cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_check);
- // At least 32 bytes left to process
-
- // Free up registers by storing them to FP registers
- for (int i = 0; i < CRC32_TMP_REG_NUM; i++) {
- movxtod(tmp[i], as_FloatRegister(2*i));
- }
-
- // Determine which loop to enter
- // Shared prologue
- ldxl(buf, G0, tmp[0]);
- inc(buf, 8);
- ldxl(buf, G0, tmp[1]);
- inc(buf, 8);
- xor3(tmp[0], crc, tmp[0]); // Fold CRC into first few bytes
- and3(crc, 0, crc); // Clear out the crc register
- // Main loop needs 128-bytes at least
- mov(128, G4);
- mov(64, tmp[2]);
- cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_main_loop_prologue);
- // Less than 64 bytes
- nop();
- cmp_and_br_short(len, tmp[2], Assembler::lessUnsigned, Assembler::pt, L_fold_tail);
- // Between 64 and 127 bytes
- set64(CRC32_CONST_96, const_96, tmp[8]);
- set64(CRC32_CONST_160, const_160, tmp[9]);
- fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[2], tmp[3], buf, 0);
- fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[4], tmp[5], buf, 16);
- fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[6], tmp[7], buf, 32);
- dec(len, 48);
- ba(L_fold_tail);
- delayed()->nop();
-
- bind(L_main_loop_prologue);
- for (int i = 2; i < 8; i++) {
- ldxl(buf, G0, tmp[i]);
- inc(buf, 8);
- }
-
- // Fold total 512 bits of polynomial on each iteration,
- // 128 bits per each of 4 parallel streams
- set64(CRC32_CONST_480, const_480, tmp[8]);
- set64(CRC32_CONST_544, const_544, tmp[9]);
-
- mov(128, G4);
- bind(L_fold_512b_loop);
- fold_128bit_crc32(tmp[1], tmp[0], const_480, const_544, tmp[9], tmp[8], buf, 0);
- fold_128bit_crc32(tmp[3], tmp[2], const_480, const_544, tmp[11], tmp[10], buf, 16);
- fold_128bit_crc32(tmp[5], tmp[4], const_480, const_544, tmp[13], tmp[12], buf, 32);
- fold_128bit_crc32(tmp[7], tmp[6], const_480, const_544, tmp[15], tmp[14], buf, 64);
- dec(len, 64);
- cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_fold_512b_loop);
-
- // Fold 512 bits to 128 bits
- bind(L_fold_512b);
- set64(CRC32_CONST_96, const_96, tmp[8]);
- set64(CRC32_CONST_160, const_160, tmp[9]);
-
- fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[3], tmp[2]);
- fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[5], tmp[4]);
- fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[7], tmp[6]);
- dec(len, 48);
-
- // Fold the rest of 128 bits data chunks
- bind(L_fold_tail);
- mov(32, G4);
- cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_fold_128b);
-
- set64(CRC32_CONST_96, const_96, tmp[8]);
- set64(CRC32_CONST_160, const_160, tmp[9]);
-
- bind(L_fold_tail_loop);
- fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[2], tmp[3], buf, 0);
- sub(len, 16, len);
- cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_fold_tail_loop);
-
- // Fold the 128 bits in tmps 0 - 1 into tmp 1
- bind(L_fold_128b);
-
- set64(CRC32_CONST_64, const_64, tmp[4]);
-
- xmulx(const_64, tmp[0], tmp[2]);
- xmulxhi(const_64, tmp[0], tmp[3]);
-
- srl(tmp[2], G0, tmp[4]);
- xmulx(const_64, tmp[4], tmp[4]);
-
- srlx(tmp[2], 32, tmp[2]);
- sllx(tmp[3], 32, tmp[3]);
- or3(tmp[2], tmp[3], tmp[2]);
-
- xor3(tmp[4], tmp[1], tmp[4]);
- xor3(tmp[4], tmp[2], tmp[1]);
- dec(len, 8);
-
- // Use table lookup for the 8 bytes left in tmp[1]
- dec(len, 8);
-
- // 8 8-bit folds to compute 32-bit CRC.
- for (int j = 0; j < 4; j++) {
- fold_8bit_crc32(tmp[1], table, tmp[2], tmp[3]);
- }
- srl(tmp[1], G0, crc); // move 32 bits to general register
- for (int j = 0; j < 4; j++) {
- fold_8bit_crc32(crc, table, tmp[3]);
- }
-
- bind(L_8byte_fold_check);
-
- // Restore int registers saved in FP registers
- for (int i = 0; i < CRC32_TMP_REG_NUM; i++) {
- movdtox(as_FloatRegister(2*i), tmp[i]);
- }
-
- ba(L_cleanup_check);
- delayed()->nop();
-
- // Table look-up method for the remaining few bytes
- bind(L_cleanup_loop);
- ldub(buf, 0, O4);
- inc(buf);
- dec(len);
- xor3(O4, crc, O4);
- and3(O4, 0xFF, O4);
- sllx(O4, 2, O4);
- lduw(table, O4, O4);
- srlx(crc, 8, crc);
- xor3(O4, crc, crc);
- bind(L_cleanup_check);
- nop();
- cmp_and_br_short(len, 0, Assembler::greaterUnsigned, Assembler::pt, L_cleanup_loop);
-
- not1(crc);
-}
-
-#define CHUNK_LEN 128 /* 128 x 8B = 1KB */
-#define CHUNK_K1 0x1307a0206 /* reverseBits(pow(x, CHUNK_LEN*8*8*3 - 32) mod P(x)) << 1 */
-#define CHUNK_K2 0x1a0f717c4 /* reverseBits(pow(x, CHUNK_LEN*8*8*2 - 32) mod P(x)) << 1 */
-#define CHUNK_K3 0x0170076fa /* reverseBits(pow(x, CHUNK_LEN*8*8*1 - 32) mod P(x)) << 1 */
-
-void MacroAssembler::kernel_crc32c(Register crc, Register buf, Register len, Register table) {
-
- Label L_crc32c_head, L_crc32c_aligned;
- Label L_crc32c_parallel, L_crc32c_parallel_loop;
- Label L_crc32c_serial, L_crc32c_x32_loop, L_crc32c_x8, L_crc32c_x8_loop;
- Label L_crc32c_done, L_crc32c_tail, L_crc32c_return;
-
- set(ExternalAddress(StubRoutines::crc32c_table_addr()), table);
-
- cmp_and_br_short(len, 0, Assembler::lessEqual, Assembler::pn, L_crc32c_return);
-
- // clear upper 32 bits of crc
- clruwu(crc);
-
- and3(buf, 7, G4);
- cmp_and_brx_short(G4, 0, Assembler::equal, Assembler::pt, L_crc32c_aligned);
-
- mov(8, G1);
- sub(G1, G4, G4);
-
- // ------ process the misaligned head (7 bytes or less) ------
- bind(L_crc32c_head);
-
- // crc = (crc >>> 8) ^ byteTable[(crc ^ b) & 0xFF];
- ldub(buf, 0, G1);
- update_byte_crc32(crc, G1, table);
-
- inc(buf);
- dec(len);
- cmp_and_br_short(len, 0, Assembler::equal, Assembler::pn, L_crc32c_return);
- dec(G4);
- cmp_and_br_short(G4, 0, Assembler::greater, Assembler::pt, L_crc32c_head);
-
- // ------ process the 8-byte-aligned body ------
- bind(L_crc32c_aligned);
- nop();
- cmp_and_br_short(len, 8, Assembler::less, Assembler::pn, L_crc32c_tail);
-
- // reverse the byte order of lower 32 bits to big endian, and move to FP side
- movitof_revbytes(crc, F0, G1, G3);
-
- set(CHUNK_LEN*8*4, G4);
- cmp_and_br_short(len, G4, Assembler::less, Assembler::pt, L_crc32c_serial);
-
- // ------ process four 1KB chunks in parallel ------
- bind(L_crc32c_parallel);
-
- fzero(FloatRegisterImpl::D, F2);
- fzero(FloatRegisterImpl::D, F4);
- fzero(FloatRegisterImpl::D, F6);
-
- mov(CHUNK_LEN - 1, G4);
- bind(L_crc32c_parallel_loop);
- // schedule ldf's ahead of crc32c's to hide the load-use latency
- ldf(FloatRegisterImpl::D, buf, 0, F8);
- ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*8, F10);
- ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*16, F12);
- ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*24, F14);
- crc32c(F0, F8, F0);
- crc32c(F2, F10, F2);
- crc32c(F4, F12, F4);
- crc32c(F6, F14, F6);
- inc(buf, 8);
- dec(G4);
- cmp_and_br_short(G4, 0, Assembler::greater, Assembler::pt, L_crc32c_parallel_loop);
-
- ldf(FloatRegisterImpl::D, buf, 0, F8);
- ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*8, F10);
- ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*16, F12);
- crc32c(F0, F8, F0);
- crc32c(F2, F10, F2);
- crc32c(F4, F12, F4);
-
- inc(buf, CHUNK_LEN*24);
- ldfl(FloatRegisterImpl::D, buf, G0, F14); // load in little endian
- inc(buf, 8);
-
- prefetch(buf, 0, Assembler::severalReads);
- prefetch(buf, CHUNK_LEN*8, Assembler::severalReads);
- prefetch(buf, CHUNK_LEN*16, Assembler::severalReads);
- prefetch(buf, CHUNK_LEN*24, Assembler::severalReads);
-
- // move to INT side, and reverse the byte order of lower 32 bits to little endian
- movftoi_revbytes(F0, O4, G1, G4);
- movftoi_revbytes(F2, O5, G1, G4);
- movftoi_revbytes(F4, G5, G1, G4);
-
- // combine the results of 4 chunks
- set64(CHUNK_K1, G3, G1);
- xmulx(O4, G3, O4);
- set64(CHUNK_K2, G3, G1);
- xmulx(O5, G3, O5);
- set64(CHUNK_K3, G3, G1);
- xmulx(G5, G3, G5);
-
- movdtox(F14, G4);
- xor3(O4, O5, O5);
- xor3(G5, O5, O5);
- xor3(G4, O5, O5);
-
- // reverse the byte order to big endian, via stack, and move to FP side
- // TODO: use new revb instruction
- add(SP, -8, G1);
- srlx(G1, 3, G1);
- sllx(G1, 3, G1);
- stx(O5, G1, G0);
- ldfl(FloatRegisterImpl::D, G1, G0, F2); // load in little endian
-
- crc32c(F6, F2, F0);
-
- set(CHUNK_LEN*8*4, G4);
- sub(len, G4, len);
- cmp_and_br_short(len, G4, Assembler::greaterEqual, Assembler::pt, L_crc32c_parallel);
- nop();
- cmp_and_br_short(len, 0, Assembler::equal, Assembler::pt, L_crc32c_done);
-
- bind(L_crc32c_serial);
-
- mov(32, G4);
- cmp_and_br_short(len, G4, Assembler::less, Assembler::pn, L_crc32c_x8);
-
- // ------ process 32B chunks ------
- bind(L_crc32c_x32_loop);
- ldf(FloatRegisterImpl::D, buf, 0, F2);
- crc32c(F0, F2, F0);
- ldf(FloatRegisterImpl::D, buf, 8, F2);
- crc32c(F0, F2, F0);
- ldf(FloatRegisterImpl::D, buf, 16, F2);
- crc32c(F0, F2, F0);
- ldf(FloatRegisterImpl::D, buf, 24, F2);
- inc(buf, 32);
- crc32c(F0, F2, F0);
- dec(len, 32);
- cmp_and_br_short(len, G4, Assembler::greaterEqual, Assembler::pt, L_crc32c_x32_loop);
-
- bind(L_crc32c_x8);
- nop();
- cmp_and_br_short(len, 8, Assembler::less, Assembler::pt, L_crc32c_done);
-
- // ------ process 8B chunks ------
- bind(L_crc32c_x8_loop);
- ldf(FloatRegisterImpl::D, buf, 0, F2);
- inc(buf, 8);
- crc32c(F0, F2, F0);
- dec(len, 8);
- cmp_and_br_short(len, 8, Assembler::greaterEqual, Assembler::pt, L_crc32c_x8_loop);
-
- bind(L_crc32c_done);
-
- // move to INT side, and reverse the byte order of lower 32 bits to little endian
- movftoi_revbytes(F0, crc, G1, G3);
-
- cmp_and_br_short(len, 0, Assembler::equal, Assembler::pt, L_crc32c_return);
-
- // ------ process the misaligned tail (7 bytes or less) ------
- bind(L_crc32c_tail);
-
- // crc = (crc >>> 8) ^ byteTable[(crc ^ b) & 0xFF];
- ldub(buf, 0, G1);
- update_byte_crc32(crc, G1, table);
-
- inc(buf);
- dec(len);
- cmp_and_br_short(len, 0, Assembler::greater, Assembler::pt, L_crc32c_tail);
-
- bind(L_crc32c_return);
- nop();
-}
diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp
deleted file mode 100644
index 0495fe57660..00000000000
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp
+++ /dev/null
@@ -1,1348 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_MACROASSEMBLER_SPARC_HPP
-#define CPU_SPARC_MACROASSEMBLER_SPARC_HPP
-
-#include "asm/assembler.hpp"
-#include "utilities/macros.hpp"
-
-// promises that the system will not use traps 16-31
-#define ST_RESERVED_FOR_USER_0 0x10
-
-class BiasedLockingCounters;
-
-
-// Register aliases for parts of the system:
-
-// 64 bit values can be kept in g1-g5, o1-o5 and o7 and all 64 bits are safe
-// across context switches in V8+ ABI. Of course, there are no 64 bit regs
-// in V8 ABI. All 64 bits are preserved in V9 ABI for all registers.
-
-// g2-g4 are scratch registers called "application globals". Their
-// meaning is reserved to the "compilation system"--which means us!
-// They are are not supposed to be touched by ordinary C code, although
-// highly-optimized C code might steal them for temps. They are safe
-// across thread switches, and the ABI requires that they be safe
-// across function calls.
-//
-// g1 and g3 are touched by more modules. V8 allows g1 to be clobbered
-// across func calls, and V8+ also allows g5 to be clobbered across
-// func calls. Also, g1 and g5 can get touched while doing shared
-// library loading.
-//
-// We must not touch g7 (it is the thread-self register) and g6 is
-// reserved for certain tools. g0, of course, is always zero.
-//
-// (Sources: SunSoft Compilers Group, thread library engineers.)
-
-// %%%% The interpreter should be revisited to reduce global scratch regs.
-
-// This global always holds the current JavaThread pointer:
-
-REGISTER_DECLARATION(Register, G2_thread , G2);
-REGISTER_DECLARATION(Register, G6_heapbase , G6);
-
-// The following globals are part of the Java calling convention:
-
-REGISTER_DECLARATION(Register, G5_method , G5);
-REGISTER_DECLARATION(Register, G5_megamorphic_method , G5_method);
-REGISTER_DECLARATION(Register, G5_inline_cache_reg , G5_method);
-
-// The following globals are used for the new C1 & interpreter calling convention:
-REGISTER_DECLARATION(Register, Gargs , G4); // pointing to the last argument
-
-// This local is used to preserve G2_thread in the interpreter and in stubs:
-REGISTER_DECLARATION(Register, L7_thread_cache , L7);
-
-// These globals are used as scratch registers in the interpreter:
-
-REGISTER_DECLARATION(Register, Gframe_size , G1); // SAME REG as G1_scratch
-REGISTER_DECLARATION(Register, G1_scratch , G1); // also SAME
-REGISTER_DECLARATION(Register, G3_scratch , G3);
-REGISTER_DECLARATION(Register, G4_scratch , G4);
-
-// These globals are used as short-lived scratch registers in the compiler:
-
-REGISTER_DECLARATION(Register, Gtemp , G5);
-
-// JSR 292 fixed register usages:
-REGISTER_DECLARATION(Register, G5_method_type , G5);
-REGISTER_DECLARATION(Register, G3_method_handle , G3);
-REGISTER_DECLARATION(Register, L7_mh_SP_save , L7);
-
-// The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
-// because a single patchable "set" instruction (NativeMovConstReg,
-// or NativeMovConstPatching for compiler1) instruction
-// serves to set up either quantity, depending on whether the compiled
-// call site is an inline cache or is megamorphic. See the function
-// CompiledIC::set_to_megamorphic.
-//
-// If a inline cache targets an interpreted method, then the
-// G5 register will be used twice during the call. First,
-// the call site will be patched to load a compiledICHolder
-// into G5. (This is an ordered pair of ic_klass, method.)
-// The c2i adapter will first check the ic_klass, then load
-// G5_method with the method part of the pair just before
-// jumping into the interpreter.
-//
-// Note that G5_method is only the method-self for the interpreter,
-// and is logically unrelated to G5_megamorphic_method.
-//
-// Invariants on G2_thread (the JavaThread pointer):
-// - it should not be used for any other purpose anywhere
-// - it must be re-initialized by StubRoutines::call_stub()
-// - it must be preserved around every use of call_VM
-
-// We can consider using g2/g3/g4 to cache more values than the
-// JavaThread, such as the card-marking base or perhaps pointers into
-// Eden. It's something of a waste to use them as scratch temporaries,
-// since they are not supposed to be volatile. (Of course, if we find
-// that Java doesn't benefit from application globals, then we can just
-// use them as ordinary temporaries.)
-//
-// Since g1 and g5 (and/or g6) are the volatile (caller-save) registers,
-// it makes sense to use them routinely for procedure linkage,
-// whenever the On registers are not applicable. Examples: G5_method,
-// G5_inline_cache_klass, and a double handful of miscellaneous compiler
-// stubs. This means that compiler stubs, etc., should be kept to a
-// maximum of two or three G-register arguments.
-
-
-// stub frames
-
-REGISTER_DECLARATION(Register, Lentry_args , L0); // pointer to args passed to callee (interpreter) not stub itself
-
-// Interpreter frames
-
-REGISTER_DECLARATION(Register, Lesp , L0); // expression stack pointer
-REGISTER_DECLARATION(Register, Lbcp , L1); // pointer to next bytecode
-REGISTER_DECLARATION(Register, Lmethod , L2);
-REGISTER_DECLARATION(Register, Llocals , L3);
-REGISTER_DECLARATION(Register, Largs , L3); // pointer to locals for signature handler
- // must match Llocals in asm interpreter
-REGISTER_DECLARATION(Register, Lmonitors , L4);
-REGISTER_DECLARATION(Register, Lbyte_code , L5);
-// When calling out from the interpreter we record SP so that we can remove any extra stack
-// space allocated during adapter transitions. This register is only live from the point
-// of the call until we return.
-REGISTER_DECLARATION(Register, Llast_SP , L5);
-REGISTER_DECLARATION(Register, Lscratch , L5);
-REGISTER_DECLARATION(Register, Lscratch2 , L6);
-REGISTER_DECLARATION(Register, LcpoolCache , L6); // constant pool cache
-
-REGISTER_DECLARATION(Register, O5_savedSP , O5);
-REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumping for locals. This is simply
- // a copy SP, so in 64-bit it's a biased value. The bias
- // is added and removed as needed in the frame code.
-REGISTER_DECLARATION(Register, IdispatchAddress , I3); // Register which saves the dispatch address for each bytecode
-REGISTER_DECLARATION(Register, ImethodDataPtr , I2); // Pointer to the current method data
-
-// NOTE: Lscratch2 and LcpoolCache point to the same registers in
-// the interpreter code. If Lscratch2 needs to be used for some
-// purpose than LcpoolCache should be restore after that for
-// the interpreter to work right
-// (These assignments must be compatible with L7_thread_cache; see above.)
-
-// Lbcp points into the middle of the method object.
-
-// Exception processing
-// These registers are passed into exception handlers.
-// All exception handlers require the exception object being thrown.
-// In addition, an nmethod's exception handler must be passed
-// the address of the call site within the nmethod, to allow
-// proper selection of the applicable catch block.
-// (Interpreter frames use their own bcp() for this purpose.)
-//
-// The Oissuing_pc value is not always needed. When jumping to a
-// handler that is known to be interpreted, the Oissuing_pc value can be
-// omitted. An actual catch block in compiled code receives (from its
-// nmethod's exception handler) the thrown exception in the Oexception,
-// but it doesn't need the Oissuing_pc.
-//
-// If an exception handler (either interpreted or compiled)
-// discovers there is no applicable catch block, it updates
-// the Oissuing_pc to the continuation PC of its own caller,
-// pops back to that caller's stack frame, and executes that
-// caller's exception handler. Obviously, this process will
-// iterate until the control stack is popped back to a method
-// containing an applicable catch block. A key invariant is
-// that the Oissuing_pc value is always a value local to
-// the method whose exception handler is currently executing.
-//
-// Note: The issuing PC value is __not__ a raw return address (I7 value).
-// It is a "return pc", the address __following__ the call.
-// Raw return addresses are converted to issuing PCs by frame::pc(),
-// or by stubs. Issuing PCs can be used directly with PC range tables.
-//
-REGISTER_DECLARATION(Register, Oexception , O0); // exception being thrown
-REGISTER_DECLARATION(Register, Oissuing_pc , O1); // where the exception is coming from
-
-// Address is an abstraction used to represent a memory location.
-//
-// Note: A register location is represented via a Register, not
-// via an address for efficiency & simplicity reasons.
-
-class Address {
- private:
- Register _base; // Base register.
- RegisterOrConstant _index_or_disp; // Index register or constant displacement.
- RelocationHolder _rspec;
-
- public:
- Address() : _base(noreg), _index_or_disp(noreg) {}
-
- Address(Register base, RegisterOrConstant index_or_disp)
- : _base(base),
- _index_or_disp(index_or_disp) {
- }
-
- Address(Register base, Register index)
- : _base(base),
- _index_or_disp(index) {
- }
-
- Address(Register base, int disp)
- : _base(base),
- _index_or_disp(disp) {
- }
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- Address(Register base, ByteSize disp)
- : _base(base),
- _index_or_disp(in_bytes(disp)) {
- }
-#endif
-
- // accessors
- Register base() const { return _base; }
- Register index() const { return _index_or_disp.as_register(); }
- int disp() const { return _index_or_disp.as_constant(); }
-
- bool has_index() const { return _index_or_disp.is_register(); }
- bool has_disp() const { return _index_or_disp.is_constant(); }
-
- bool uses(Register reg) const { return base() == reg || (has_index() && index() == reg); }
-
- const relocInfo::relocType rtype() { return _rspec.type(); }
- const RelocationHolder& rspec() { return _rspec; }
-
- RelocationHolder rspec(int offset) const {
- return offset == 0 ? _rspec : _rspec.plus(offset);
- }
-
- inline bool is_simm13(int offset = 0); // check disp+offset for overflow
-
- Address plus_disp(int plusdisp) const { // bump disp by a small amount
- assert(_index_or_disp.is_constant(), "must have a displacement");
- Address a(base(), disp() + plusdisp);
- return a;
- }
- bool is_same_address(Address a) const {
- // disregard _rspec
- return base() == a.base() && (has_index() ? index() == a.index() : disp() == a.disp());
- }
-
- Address after_save() const {
- Address a = (*this);
- a._base = a._base->after_save();
- return a;
- }
-
- Address after_restore() const {
- Address a = (*this);
- a._base = a._base->after_restore();
- return a;
- }
-
- // Convert the raw encoding form into the form expected by the
- // constructor for Address.
- static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc);
-
- friend class Assembler;
-};
-
-
-class AddressLiteral {
- private:
- address _address;
- RelocationHolder _rspec;
-
- RelocationHolder rspec_from_rtype(relocInfo::relocType rtype, address addr) {
- switch (rtype) {
- case relocInfo::external_word_type:
- return external_word_Relocation::spec(addr);
- case relocInfo::internal_word_type:
- return internal_word_Relocation::spec(addr);
- case relocInfo::opt_virtual_call_type:
- return opt_virtual_call_Relocation::spec();
- case relocInfo::static_call_type:
- return static_call_Relocation::spec();
- case relocInfo::runtime_call_type:
- return runtime_call_Relocation::spec();
- case relocInfo::none:
- return RelocationHolder();
- default:
- ShouldNotReachHere();
- return RelocationHolder();
- }
- }
-
- protected:
- // creation
- AddressLiteral() : _address(NULL), _rspec(NULL) {}
-
- public:
- AddressLiteral(address addr, RelocationHolder const& rspec)
- : _address(addr),
- _rspec(rspec) {}
-
- // Some constructors to avoid casting at the call site.
- AddressLiteral(jobject obj, RelocationHolder const& rspec)
- : _address((address) obj),
- _rspec(rspec) {}
-
- AddressLiteral(intptr_t value, RelocationHolder const& rspec)
- : _address((address) value),
- _rspec(rspec) {}
-
- AddressLiteral(address addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- // Some constructors to avoid casting at the call site.
- AddressLiteral(address* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(bool* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(const bool* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(signed char* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(int* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(intptr_t addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- // 32-bit complains about a multiple declaration for int*.
- AddressLiteral(intptr_t* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(Metadata* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(Metadata** addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(float* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(double* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- intptr_t value() const { return (intptr_t) _address; }
- int low10() const;
-
- const relocInfo::relocType rtype() const { return _rspec.type(); }
- const RelocationHolder& rspec() const { return _rspec; }
-
- RelocationHolder rspec(int offset) const {
- return offset == 0 ? _rspec : _rspec.plus(offset);
- }
-};
-
-// Convenience classes
-class ExternalAddress: public AddressLiteral {
- private:
- static relocInfo::relocType reloc_for_target(address target) {
- // Sometimes ExternalAddress is used for values which aren't
- // exactly addresses, like the card table base.
- // external_word_type can't be used for values in the first page
- // so just skip the reloc in that case.
- return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
- }
-
- public:
- ExternalAddress(address target) : AddressLiteral(target, reloc_for_target( target)) {}
- ExternalAddress(Metadata** target) : AddressLiteral(target, reloc_for_target((address) target)) {}
-};
-
-inline Address RegisterImpl::address_in_saved_window() const {
- return (Address(SP, (sp_offset_in_saved_window() * wordSize) + STACK_BIAS));
-}
-
-
-
-// Argument is an abstraction used to represent an outgoing
-// actual argument or an incoming formal parameter, whether
-// it resides in memory or in a register, in a manner consistent
-// with the SPARC Application Binary Interface, or ABI. This is
-// often referred to as the native or C calling convention.
-
-class Argument {
- private:
- int _number;
- bool _is_in;
-
- public:
- enum {
- n_register_parameters = 6, // only 6 registers may contain integer parameters
- n_float_register_parameters = 16 // Can have up to 16 floating registers
- };
-
- // creation
- Argument(int number, bool is_in) : _number(number), _is_in(is_in) {}
-
- int number() const { return _number; }
- bool is_in() const { return _is_in; }
- bool is_out() const { return !is_in(); }
-
- Argument successor() const { return Argument(number() + 1, is_in()); }
- Argument as_in() const { return Argument(number(), true ); }
- Argument as_out() const { return Argument(number(), false); }
-
- // locating register-based arguments:
- bool is_register() const { return _number < n_register_parameters; }
-
- // locating Floating Point register-based arguments:
- bool is_float_register() const { return _number < n_float_register_parameters; }
-
- FloatRegister as_float_register() const {
- assert(is_float_register(), "must be a register argument");
- return as_FloatRegister(( number() *2 ) + 1);
- }
- FloatRegister as_double_register() const {
- assert(is_float_register(), "must be a register argument");
- return as_FloatRegister(( number() *2 ));
- }
-
- Register as_register() const {
- assert(is_register(), "must be a register argument");
- return is_in() ? as_iRegister(number()) : as_oRegister(number());
- }
-
- // locating memory-based arguments
- Address as_address() const {
- assert(!is_register(), "must be a memory argument");
- return address_in_frame();
- }
-
- // When applied to a register-based argument, give the corresponding address
- // into the 6-word area "into which callee may store register arguments"
- // (This is a different place than the corresponding register-save area location.)
- Address address_in_frame() const;
-
- // debugging
- const char* name() const;
-
- friend class Assembler;
-};
-
-
-class RegistersForDebugging : public StackObj {
- private:
- static const RegistersForDebugging& _dummy; // not ODR-used so not defined
-
- public:
- intptr_t i[8], l[8], o[8], g[8];
- float f[32];
- double d[32];
-
- void print(outputStream* s);
-
- static int i_offset(int j) { return offset_of(RegistersForDebugging, i) + j * sizeof(_dummy.i[0]); }
- static int l_offset(int j) { return offset_of(RegistersForDebugging, l) + j * sizeof(_dummy.l[0]); }
- static int o_offset(int j) { return offset_of(RegistersForDebugging, o) + j * sizeof(_dummy.o[0]); }
- static int g_offset(int j) { return offset_of(RegistersForDebugging, g) + j * sizeof(_dummy.g[0]); }
- static int f_offset(int j) { return offset_of(RegistersForDebugging, f) + j * sizeof(_dummy.f[0]); }
- static int d_offset(int j) { return offset_of(RegistersForDebugging, d) + (j / 2) * sizeof(_dummy.d[0]); }
-
- // gen asm code to save regs
- static void save_registers(MacroAssembler* a);
-
- // restore global registers in case C code disturbed them
- static void restore_registers(MacroAssembler* a, Register r);
-};
-
-
-// MacroAssembler extends Assembler by a few frequently used macros.
-//
-// Most of the standard SPARC synthetic ops are defined here.
-// Instructions for which a 'better' code sequence exists depending
-// on arguments should also go in here.
-
-#define JMP2(r1, r2) jmp(r1, r2, __FILE__, __LINE__)
-#define JMP(r1, off) jmp(r1, off, __FILE__, __LINE__)
-#define JUMP(a, temp, off) jump(a, temp, off, __FILE__, __LINE__)
-#define JUMPL(a, temp, d, off) jumpl(a, temp, d, off, __FILE__, __LINE__)
-
-
-class MacroAssembler : public Assembler {
- // code patchers need various routines like inv_wdisp()
- friend class NativeInstruction;
- friend class NativeGeneralJump;
- friend class Relocation;
- friend class Label;
-
- protected:
- static int patched_branch(int dest_pos, int inst, int inst_pos);
- static int branch_destination(int inst, int pos);
-
- // Support for VM calls
- // This is the base routine called by the different versions of call_VM_leaf. The interpreter
- // may customize this version by overriding it for its purposes (e.g., to save/restore
- // additional registers when doing a VM call).
- virtual void call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments);
-
- //
- // It is imperative that all calls into the VM are handled via the call_VM macros.
- // They make sure that the stack linkage is setup correctly. call_VM's correspond
- // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points.
- //
- // This is the base routine called by the different versions of call_VM. The interpreter
- // may customize this version by overriding it for its purposes (e.g., to save/restore
- // additional registers when doing a VM call).
- //
- // A non-volatile java_thread_cache register should be specified so
- // that the G2_thread value can be preserved across the call.
- // (If java_thread_cache is noreg, then a slow get_thread call
- // will re-initialize the G2_thread.) call_VM_base returns the register that contains the
- // thread.
- //
- // If no last_java_sp is specified (noreg) than SP will be used instead.
-
- virtual void call_VM_base(
- Register oop_result, // where an oop-result ends up if any; use noreg otherwise
- Register java_thread_cache, // the thread if computed before ; use noreg otherwise
- Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise
- address entry_point, // the entry point
- int number_of_arguments, // the number of arguments (w/o thread) to pop after call
- bool check_exception=true // flag which indicates if exception should be checked
- );
-
- public:
- MacroAssembler(CodeBuffer* code) : Assembler(code) {}
-
- // This routine should emit JVMTI PopFrame and ForceEarlyReturn handling code.
- // The implementation is only non-empty for the InterpreterMacroAssembler,
- // as only the interpreter handles and ForceEarlyReturn PopFrame requests.
- virtual void check_and_handle_popframe(Register scratch_reg);
- virtual void check_and_handle_earlyret(Register scratch_reg);
-
- // Support for NULL-checks
- //
- // Generates code that causes a NULL OS exception if the content of reg is NULL.
- // If the accessed location is M[reg + offset] and the offset is known, provide the
- // offset. No explicit code generation is needed if the offset is within a certain
- // range (0 <= offset <= page_size).
- //
- // FIXME: Currently not done for SPARC
-
- void null_check(Register reg, int offset = -1);
- static bool needs_explicit_null_check(intptr_t offset);
- static bool uses_implicit_null_check(void* address);
-
- // support for delayed instructions
- MacroAssembler* delayed() { Assembler::delayed(); return this; }
-
- // branches that use right instruction for v8 vs. v9
- inline void br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void br( Condition c, bool a, Predict p, Label& L );
-
- inline void fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void fb( Condition c, bool a, Predict p, Label& L );
-
- // compares register with zero (32 bit) and branches (V9 and V8 instructions)
- void cmp_zero_and_br( Condition c, Register s1, Label& L, bool a = false, Predict p = pn );
- // Compares a pointer register with zero and branches on (not)null.
- // Does a test & branch on 32-bit systems and a register-branch on 64-bit.
- void br_null ( Register s1, bool a, Predict p, Label& L );
- void br_notnull( Register s1, bool a, Predict p, Label& L );
-
- //
- // Compare registers and branch with nop in delay slot or cbcond without delay slot.
- //
- // ATTENTION: use these instructions with caution because cbcond instruction
- // has very short distance: 512 instructions (2Kbyte).
-
- // Compare integer (32 bit) values (icc only).
- void cmp_and_br_short(Register s1, Register s2, Condition c, Predict p, Label& L);
- void cmp_and_br_short(Register s1, int simm13a, Condition c, Predict p, Label& L);
- // Platform depending version for pointer compare (icc on !LP64 and xcc on LP64).
- void cmp_and_brx_short(Register s1, Register s2, Condition c, Predict p, Label& L);
- void cmp_and_brx_short(Register s1, int simm13a, Condition c, Predict p, Label& L);
-
- // Short branch version for compares a pointer pwith zero.
- void br_null_short ( Register s1, Predict p, Label& L );
- void br_notnull_short( Register s1, Predict p, Label& L );
-
- // unconditional short branch
- void ba_short(Label& L);
-
- // Branch on icc.z (true or not).
- void br_icc_zero(bool iszero, Predict p, Label &L);
-
- inline void bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void bp( Condition c, bool a, CC cc, Predict p, Label& L );
-
- // Branch that tests xcc in LP64 and icc in !LP64
- inline void brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void brx( Condition c, bool a, Predict p, Label& L );
-
- // unconditional branch
- inline void ba( Label& L );
-
- // Branch that tests fp condition codes
- inline void fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void fbp( Condition c, bool a, CC cc, Predict p, Label& L );
-
- // Sparc shorthands(pp 85, V8 manual, pp 289 V9 manual)
- inline void cmp( Register s1, Register s2 );
- inline void cmp( Register s1, int simm13a );
-
- inline void jmp( Register s1, Register s2 );
- inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() );
-
- // Check if the call target is out of wdisp30 range (relative to the code cache)
- static inline bool is_far_target(address d);
- inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type );
- inline void call( address d, RelocationHolder const& rspec);
-
- inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type );
- inline void call( Label& L, RelocationHolder const& rspec);
-
- inline void callr( Register s1, Register s2 );
- inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() );
-
- inline void tst( Register s );
-
- inline void ret( bool trace = false );
- inline void retl( bool trace = false );
-
- // Required platform-specific helpers for Label::patch_instructions.
- // They _shadow_ the declarations in AbstractAssembler, which are undefined.
- void pd_patch_instruction(address branch, address target, const char* file, int line);
-
- // sethi Macro handles optimizations and relocations
-private:
- void internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable);
-public:
- void sethi(const AddressLiteral& addrlit, Register d);
- void patchable_sethi(const AddressLiteral& addrlit, Register d);
-
- // compute the number of instructions for a sethi/set
- static int insts_for_sethi( address a, bool worst_case = false );
- static int worst_case_insts_for_set();
-
- // set may be either setsw or setuw (high 32 bits may be zero or sign)
-private:
- void internal_set(const AddressLiteral& al, Register d, bool ForceRelocatable);
- static int insts_for_internal_set(intptr_t value);
-public:
- void set(const AddressLiteral& addrlit, Register d);
- void set(intptr_t value, Register d);
- void set(address addr, Register d, RelocationHolder const& rspec);
- static int insts_for_set(intptr_t value) { return insts_for_internal_set(value); }
-
- void patchable_set(const AddressLiteral& addrlit, Register d);
- void patchable_set(intptr_t value, Register d);
- void set64(jlong value, Register d, Register tmp);
- static int insts_for_set64(jlong value);
-
- // sign-extend 32 to 64
- inline void signx( Register s, Register d );
- inline void signx( Register d );
-
- inline void not1( Register s, Register d );
- inline void not1( Register d );
-
- inline void neg( Register s, Register d );
- inline void neg( Register d );
-
- inline void cas( Register s1, Register s2, Register d);
- inline void casx( Register s1, Register s2, Register d);
- // Functions for isolating 64 bit atomic swaps for LP64
- // cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's
- inline void cas_ptr( Register s1, Register s2, Register d);
-
- // Resolve a jobject or jweak
- void resolve_jobject(Register value, Register tmp);
-
- // Functions for isolating 64 bit shifts for LP64
- inline void sll_ptr( Register s1, Register s2, Register d );
- inline void sll_ptr( Register s1, int imm6a, Register d );
- inline void sll_ptr( Register s1, RegisterOrConstant s2, Register d );
- inline void srl_ptr( Register s1, Register s2, Register d );
- inline void srl_ptr( Register s1, int imm6a, Register d );
-
- // little-endian
- inline void casl( Register s1, Register s2, Register d);
- inline void casxl( Register s1, Register s2, Register d);
-
- inline void inc( Register d, int const13 = 1 );
- inline void inccc( Register d, int const13 = 1 );
-
- inline void dec( Register d, int const13 = 1 );
- inline void deccc( Register d, int const13 = 1 );
-
- using Assembler::add;
- inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype);
- inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec);
- inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
- inline void add(const Address& a, Register d, int offset = 0);
-
- using Assembler::andn;
- inline void andn( Register s1, RegisterOrConstant s2, Register d);
-
- inline void btst( Register s1, Register s2 );
- inline void btst( int simm13a, Register s );
-
- inline void bset( Register s1, Register s2 );
- inline void bset( int simm13a, Register s );
-
- inline void bclr( Register s1, Register s2 );
- inline void bclr( int simm13a, Register s );
-
- inline void btog( Register s1, Register s2 );
- inline void btog( int simm13a, Register s );
-
- inline void clr( Register d );
-
- inline void clrb( Register s1, Register s2);
- inline void clrh( Register s1, Register s2);
- inline void clr( Register s1, Register s2);
- inline void clrx( Register s1, Register s2);
-
- inline void clrb( Register s1, int simm13a);
- inline void clrh( Register s1, int simm13a);
- inline void clr( Register s1, int simm13a);
- inline void clrx( Register s1, int simm13a);
-
- // copy & clear upper word
- inline void clruw( Register s, Register d );
- // clear upper word
- inline void clruwu( Register d );
-
- using Assembler::ldsb;
- using Assembler::ldsh;
- using Assembler::ldsw;
- using Assembler::ldub;
- using Assembler::lduh;
- using Assembler::lduw;
- using Assembler::ldx;
- using Assembler::ldd;
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- inline void ld(Register s1, ByteSize simm13a, Register d);
-#endif
-
- inline void ld(Register s1, Register s2, Register d);
- inline void ld(Register s1, int simm13a, Register d);
-
- inline void ldsb(const Address& a, Register d, int offset = 0);
- inline void ldsh(const Address& a, Register d, int offset = 0);
- inline void ldsw(const Address& a, Register d, int offset = 0);
- inline void ldub(const Address& a, Register d, int offset = 0);
- inline void lduh(const Address& a, Register d, int offset = 0);
- inline void lduw(const Address& a, Register d, int offset = 0);
- inline void ldx( const Address& a, Register d, int offset = 0);
- inline void ld( const Address& a, Register d, int offset = 0);
- inline void ldd( const Address& a, Register d, int offset = 0);
-
- inline void ldub(Register s1, RegisterOrConstant s2, Register d );
- inline void ldsb(Register s1, RegisterOrConstant s2, Register d );
- inline void lduh(Register s1, RegisterOrConstant s2, Register d );
- inline void ldsh(Register s1, RegisterOrConstant s2, Register d );
- inline void lduw(Register s1, RegisterOrConstant s2, Register d );
- inline void ldsw(Register s1, RegisterOrConstant s2, Register d );
- inline void ldx( Register s1, RegisterOrConstant s2, Register d );
- inline void ld( Register s1, RegisterOrConstant s2, Register d );
- inline void ldd( Register s1, RegisterOrConstant s2, Register d );
-
- using Assembler::ldf;
- inline void ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d);
- inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0);
-
- // little-endian
- inline void lduwl(Register s1, Register s2, Register d);
- inline void ldswl(Register s1, Register s2, Register d);
- inline void ldxl( Register s1, Register s2, Register d);
- inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d);
-
- // membar psuedo instruction. takes into account target memory model.
- inline void membar( Assembler::Membar_mask_bits const7a );
-
- // returns if membar generates anything.
- inline bool membar_has_effect( Assembler::Membar_mask_bits const7a );
-
- // mov pseudo instructions
- inline void mov( Register s, Register d);
-
- inline void mov_or_nop( Register s, Register d);
-
- inline void mov( int simm13a, Register d);
-
- using Assembler::prefetch;
- inline void prefetch(const Address& a, PrefetchFcn F, int offset = 0);
-
- using Assembler::stb;
- using Assembler::sth;
- using Assembler::stw;
- using Assembler::stx;
- using Assembler::std;
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- inline void st(Register d, Register s1, ByteSize simm13a);
-#endif
-
- inline void st(Register d, Register s1, Register s2);
- inline void st(Register d, Register s1, int simm13a);
-
- inline void stb(Register d, const Address& a, int offset = 0 );
- inline void sth(Register d, const Address& a, int offset = 0 );
- inline void stw(Register d, const Address& a, int offset = 0 );
- inline void stx(Register d, const Address& a, int offset = 0 );
- inline void st( Register d, const Address& a, int offset = 0 );
- inline void std(Register d, const Address& a, int offset = 0 );
-
- inline void stb(Register d, Register s1, RegisterOrConstant s2 );
- inline void sth(Register d, Register s1, RegisterOrConstant s2 );
- inline void stw(Register d, Register s1, RegisterOrConstant s2 );
- inline void stx(Register d, Register s1, RegisterOrConstant s2 );
- inline void std(Register d, Register s1, RegisterOrConstant s2 );
- inline void st( Register d, Register s1, RegisterOrConstant s2 );
-
- using Assembler::stf;
- inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2);
- inline void stf(FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset = 0);
-
- // Note: offset is added to s2.
- using Assembler::sub;
- inline void sub(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
-
- using Assembler::swap;
- inline void swap(const Address& a, Register d, int offset = 0);
-
- // address pseudos: make these names unlike instruction names to avoid confusion
- inline intptr_t load_pc_address( Register reg, int bytes_to_skip );
- inline void load_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
- inline void load_bool_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
- inline void load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
- inline void store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0);
- inline void store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0);
- inline void jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset = 0);
- inline void jump_to(const AddressLiteral& addrlit, Register temp, int offset = 0);
- inline void jump_indirect_to(Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0);
-
- // ring buffer traceable jumps
-
- void jmp2( Register r1, Register r2, const char* file, int line );
- void jmp ( Register r1, int offset, const char* file, int line );
-
- void jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line);
- void jump (const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line);
-
-
- // argument pseudos:
-
- inline void load_argument( Argument& a, Register d );
- inline void store_argument( Register s, Argument& a );
- inline void store_ptr_argument( Register s, Argument& a );
- inline void store_float_argument( FloatRegister s, Argument& a );
- inline void store_double_argument( FloatRegister s, Argument& a );
- inline void store_long_argument( Register s, Argument& a );
-
- // handy macros:
-
- inline void round_to( Register r, int modulus );
-
- // --------------------------------------------------
-
- // Functions for isolating 64 bit loads for LP64
- // ld_ptr will perform ld for 32 bit VM's and ldx for 64 bit VM's
- // st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's
- inline void ld_ptr(Register s1, Register s2, Register d);
- inline void ld_ptr(Register s1, int simm13a, Register d);
- inline void ld_ptr(Register s1, RegisterOrConstant s2, Register d);
- inline void ld_ptr(const Address& a, Register d, int offset = 0);
- inline void st_ptr(Register d, Register s1, Register s2);
- inline void st_ptr(Register d, Register s1, int simm13a);
- inline void st_ptr(Register d, Register s1, RegisterOrConstant s2);
- inline void st_ptr(Register d, const Address& a, int offset = 0);
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- inline void ld_ptr(Register s1, ByteSize simm13a, Register d);
- inline void st_ptr(Register d, Register s1, ByteSize simm13a);
-#endif
-
- // ld_long will perform ldd for 32 bit VM's and ldx for 64 bit VM's
- // st_long will perform std for 32 bit VM's and stx for 64 bit VM's
- inline void ld_long(Register s1, Register s2, Register d);
- inline void ld_long(Register s1, int simm13a, Register d);
- inline void ld_long(Register s1, RegisterOrConstant s2, Register d);
- inline void ld_long(const Address& a, Register d, int offset = 0);
- inline void st_long(Register d, Register s1, Register s2);
- inline void st_long(Register d, Register s1, int simm13a);
- inline void st_long(Register d, Register s1, RegisterOrConstant s2);
- inline void st_long(Register d, const Address& a, int offset = 0);
-
- // Helpers for address formation.
- // - They emit only a move if s2 is a constant zero.
- // - If dest is a constant and either s1 or s2 is a register, the temp argument is required and becomes the result.
- // - If dest is a register and either s1 or s2 is a non-simm13 constant, the temp argument is required and used to materialize the constant.
- RegisterOrConstant regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
- RegisterOrConstant regcon_inc_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
- RegisterOrConstant regcon_sll_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
-
- RegisterOrConstant ensure_simm13_or_reg(RegisterOrConstant src, Register temp) {
- if (is_simm13(src.constant_or_zero()))
- return src; // register or short constant
- guarantee(temp != noreg, "constant offset overflow");
- set(src.as_constant(), temp);
- return temp;
- }
-
- // --------------------------------------------------
-
- public:
- // traps as per trap.h (SPARC ABI?)
-
- void breakpoint_trap();
- void breakpoint_trap(Condition c, CC cc);
-
- void safepoint_poll(Label& slow_path, bool a, Register thread_reg, Register temp_reg);
-
- // Stack frame creation/removal
- void enter();
- void leave();
-
- // Manipulation of C++ bools
- // These are idioms to flag the need for care with accessing bools but on
- // this platform we assume byte size
-
- inline void stbool(Register d, const Address& a);
- inline void ldbool(const Address& a, Register d);
- inline void movbool( bool boolconst, Register d);
-
- void resolve_oop_handle(Register result, Register tmp);
- void load_mirror(Register mirror, Register method, Register tmp);
-
- // klass oop manipulations if compressed
- void load_klass(Register src_oop, Register klass);
- void store_klass(Register klass, Register dst_oop);
- void store_klass_gap(Register s, Register dst_oop);
-
- // oop manipulations
- void access_store_at(BasicType type, DecoratorSet decorators,
- Register src, Address dst, Register tmp);
- void access_load_at(BasicType type, DecoratorSet decorators,
- Address src, Register dst, Register tmp);
-
- void load_heap_oop(const Address& s, Register d,
- Register tmp = noreg, DecoratorSet decorators = 0);
- void load_heap_oop(Register s1, Register s2, Register d,
- Register tmp = noreg, DecoratorSet decorators = 0);
- void load_heap_oop(Register s1, int simm13a, Register d,
- Register tmp = noreg, DecoratorSet decorators = 0);
- void load_heap_oop(Register s1, RegisterOrConstant s2, Register d,
- Register tmp = noreg, DecoratorSet decorators = 0);
- void store_heap_oop(Register d, Register s1, Register s2,
- Register tmp = noreg, DecoratorSet decorators = 0);
- void store_heap_oop(Register d, Register s1, int simm13a,
- Register tmp = noreg, DecoratorSet decorators = 0);
- void store_heap_oop(Register d, const Address& a, int offset = 0,
- Register tmp = noreg, DecoratorSet decorators = 0);
-
- void encode_heap_oop(Register src, Register dst);
- void encode_heap_oop(Register r) {
- encode_heap_oop(r, r);
- }
- void decode_heap_oop(Register src, Register dst);
- void decode_heap_oop(Register r) {
- decode_heap_oop(r, r);
- }
- void encode_heap_oop_not_null(Register r);
- void decode_heap_oop_not_null(Register r);
- void encode_heap_oop_not_null(Register src, Register dst);
- void decode_heap_oop_not_null(Register src, Register dst);
-
- void encode_klass_not_null(Register r);
- void decode_klass_not_null(Register r);
- void encode_klass_not_null(Register src, Register dst);
- void decode_klass_not_null(Register src, Register dst);
-
- // Support for managing the JavaThread pointer (i.e.; the reference to
- // thread-local information).
- void get_thread(); // load G2_thread
- void verify_thread(); // verify G2_thread contents
- void save_thread (const Register threache); // save to cache
- void restore_thread(const Register thread_cache); // restore from cache
-
- // Support for last Java frame (but use call_VM instead where possible)
- void set_last_Java_frame(Register last_java_sp, Register last_Java_pc);
- void reset_last_Java_frame(void);
-
- // Call into the VM.
- // Passes the thread pointer (in O0) as a prepended argument.
- // Makes sure oop return values are visible to the GC.
- void call_VM(Register oop_result, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
- void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true);
- void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
- void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
-
- // these overloadings are not presently used on SPARC:
- void call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
- void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true);
- void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
- void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
-
- void call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments = 0);
- void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1);
- void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2);
- void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3);
-
- void get_vm_result (Register oop_result);
- void get_vm_result_2(Register metadata_result);
-
- // vm result is currently getting hijacked to for oop preservation
- void set_vm_result(Register oop_result);
-
- // Emit the CompiledIC call idiom
- void ic_call(address entry, bool emit_delay = true, jint method_index = 0);
-
- // if call_VM_base was called with check_exceptions=false, then call
- // check_and_forward_exception to handle exceptions when it is safe
- void check_and_forward_exception(Register scratch_reg);
-
- // Returns the byte size of the instructions generated by decode_klass_not_null().
- static int instr_size_for_decode_klass_not_null();
-
- // if heap base register is used - reinit it with the correct value
- void reinit_heapbase();
-
- // Debugging
- void _verify_oop(Register reg, const char * msg, const char * file, int line);
- void _verify_oop_addr(Address addr, const char * msg, const char * file, int line);
-
- // TODO: verify_method and klass metadata (compare against vptr?)
- void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
- void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){}
-
-#define verify_oop(reg) _verify_oop(reg, "broken oop " #reg, __FILE__, __LINE__)
-#define verify_oop_addr(addr) _verify_oop_addr(addr, "broken oop addr ", __FILE__, __LINE__)
-#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
-#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
-
- void stop(const char* msg); // prints msg, dumps registers and stops execution
- void warn(const char* msg); // prints msg, but don't stop
- void untested(const char* what = "");
- void unimplemented(const char* what = "");
- void should_not_reach_here() { stop("should not reach here"); }
-
- // oops in code
- AddressLiteral allocate_oop_address(jobject obj); // allocate_index
- AddressLiteral constant_oop_address(jobject obj); // find_index
- inline void set_oop (jobject obj, Register d); // uses allocate_oop_address
- inline void set_oop_constant (jobject obj, Register d); // uses constant_oop_address
- inline void set_oop (const AddressLiteral& obj_addr, Register d); // same as load_address
-
- // metadata in code that we have to keep track of
- AddressLiteral allocate_metadata_address(Metadata* obj); // allocate_index
- AddressLiteral constant_metadata_address(Metadata* obj); // find_index
- inline void set_metadata (Metadata* obj, Register d); // uses allocate_metadata_address
- inline void set_metadata_constant (Metadata* obj, Register d); // uses constant_metadata_address
- inline void set_metadata (const AddressLiteral& obj_addr, Register d); // same as load_address
-
- void set_narrow_oop( jobject obj, Register d );
- void set_narrow_klass( Klass* k, Register d );
-
- // nop padding
- void align(int modulus);
-
- // declare a safepoint
- void safepoint();
-
- // factor out part of stop into subroutine to save space
- void stop_subroutine();
- // factor out part of verify_oop into subroutine to save space
- void verify_oop_subroutine();
-
- // side-door communication with signalHandler in os_solaris.cpp
- static address _verify_oop_implicit_branch[3];
-
- int total_frame_size_in_bytes(int extraWords);
-
- // used when extraWords known statically
- void save_frame(int extraWords = 0);
- void save_frame_c1(int size_in_bytes);
- // make a frame, and simultaneously pass up one or two register value
- // into the new register window
- void save_frame_and_mov(int extraWords, Register s1, Register d1, Register s2 = Register(), Register d2 = Register());
-
- // give no. (outgoing) params, calc # of words will need on frame
- void calc_mem_param_words(Register Rparam_words, Register Rresult);
-
- // used to calculate frame size dynamically
- // result is in bytes and must be negated for save inst
- void calc_frame_size(Register extraWords, Register resultReg);
-
- // calc and also save
- void calc_frame_size_and_save(Register extraWords, Register resultReg);
-
- static void debug(char* msg, RegistersForDebugging* outWindow);
-
- // implementations of bytecodes used by both interpreter and compiler
-
- void lcmp( Register Ra_hi, Register Ra_low,
- Register Rb_hi, Register Rb_low,
- Register Rresult);
-
- void lneg( Register Rhi, Register Rlow );
-
- void lshl( Register Rin_high, Register Rin_low, Register Rcount,
- Register Rout_high, Register Rout_low, Register Rtemp );
-
- void lshr( Register Rin_high, Register Rin_low, Register Rcount,
- Register Rout_high, Register Rout_low, Register Rtemp );
-
- void lushr( Register Rin_high, Register Rin_low, Register Rcount,
- Register Rout_high, Register Rout_low, Register Rtemp );
-
- void lcmp( Register Ra, Register Rb, Register Rresult);
-
- // Load and store values by size and signed-ness
- void load_sized_value( Address src, Register dst, size_t size_in_bytes, bool is_signed);
- void store_sized_value(Register src, Address dst, size_t size_in_bytes);
-
- void float_cmp( bool is_float, int unordered_result,
- FloatRegister Fa, FloatRegister Fb,
- Register Rresult);
-
- void save_all_globals_into_locals();
- void restore_globals_from_locals();
-
- // These set the icc condition code to equal if the lock succeeded
- // and notEqual if it failed and requires a slow case
- void compiler_lock_object(Register Roop, Register Rmark, Register Rbox,
- Register Rscratch,
- BiasedLockingCounters* counters = NULL,
- bool try_bias = UseBiasedLocking);
- void compiler_unlock_object(Register Roop, Register Rmark, Register Rbox,
- Register Rscratch,
- bool try_bias = UseBiasedLocking);
-
- // Biased locking support
- // Upon entry, lock_reg must point to the lock record on the stack,
- // obj_reg must contain the target object, and mark_reg must contain
- // the target object's header.
- // Destroys mark_reg if an attempt is made to bias an anonymously
- // biased lock. In this case a failure will go either to the slow
- // case or fall through with the notEqual condition code set with
- // the expectation that the slow case in the runtime will be called.
- // In the fall-through case where the CAS-based lock is done,
- // mark_reg is not destroyed.
- void biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg,
- Label& done, Label* slow_case = NULL,
- BiasedLockingCounters* counters = NULL);
- // Upon entry, the base register of mark_addr must contain the oop.
- // Destroys temp_reg.
-
- // If allow_delay_slot_filling is set to true, the next instruction
- // emitted after this one will go in an annulled delay slot if the
- // biased locking exit case failed.
- void biased_locking_exit(Address mark_addr, Register temp_reg, Label& done, bool allow_delay_slot_filling = false);
-
- // allocation
- void eden_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- Label& slow_case // continuation point if fast allocation fails
- );
- void tlab_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Label& slow_case // continuation point if fast allocation fails
- );
- void zero_memory(Register base, Register index);
- void incr_allocated_bytes(RegisterOrConstant size_in_bytes,
- Register t1, Register t2);
-
- // interface method calling
- void lookup_interface_method(Register recv_klass,
- Register intf_klass,
- RegisterOrConstant itable_index,
- Register method_result,
- Register temp_reg, Register temp2_reg,
- Label& no_such_interface,
- bool return_method = true);
-
- // virtual method calling
- void lookup_virtual_method(Register recv_klass,
- RegisterOrConstant vtable_index,
- Register method_result);
-
- // Test sub_klass against super_klass, with fast and slow paths.
-
- // The fast path produces a tri-state answer: yes / no / maybe-slow.
- // One of the three labels can be NULL, meaning take the fall-through.
- // If super_check_offset is -1, the value is loaded up from super_klass.
- // No registers are killed, except temp_reg and temp2_reg.
- // If super_check_offset is not -1, temp2_reg is not used and can be noreg.
- void check_klass_subtype_fast_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label* L_success,
- Label* L_failure,
- Label* L_slow_path,
- RegisterOrConstant super_check_offset = RegisterOrConstant(-1));
-
- // The rest of the type check; must be wired to a corresponding fast path.
- // It does not repeat the fast path logic, so don't use it standalone.
- // The temp_reg can be noreg, if no temps are available.
- // It can also be sub_klass or super_klass, meaning it's OK to kill that one.
- // Updates the sub's secondary super cache as necessary.
- void check_klass_subtype_slow_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Register temp3_reg,
- Register temp4_reg,
- Label* L_success,
- Label* L_failure);
-
- // Simplified, combined version, good for typical uses.
- // Falls through on failure.
- void check_klass_subtype(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label& L_success);
-
- // method handles (JSR 292)
- // offset relative to Gargs of argument at tos[arg_slot].
- // (arg_slot == 0 means the last argument, not the first).
- RegisterOrConstant argument_offset(RegisterOrConstant arg_slot,
- Register temp_reg,
- int extra_slot_offset = 0);
- // Address of Gargs and argument_offset.
- Address argument_address(RegisterOrConstant arg_slot,
- Register temp_reg = noreg,
- int extra_slot_offset = 0);
-
- // Stack overflow checking
-
- // Note: this clobbers G3_scratch
- void bang_stack_with_offset(int offset);
-
- // Writes to stack successive pages until offset reached to check for
- // stack overflow + shadow pages. Clobbers tsp and scratch registers.
- void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch);
-
- // Check for reserved stack access in method being exited (for JIT)
- void reserved_stack_check();
-
- virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset);
-
- void verify_tlab();
-
- Condition negate_condition(Condition cond);
-
- // Helper functions for statistics gathering.
- // Conditionally (non-atomically) increments passed counter address, preserving condition codes.
- void cond_inc(Condition cond, address counter_addr, Register Rtemp1, Register Rtemp2);
- // Unconditional increment.
- void inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2);
- void inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2);
-
- // Use BIS for zeroing
- void bis_zeroing(Register to, Register count, Register temp, Label& Ldone);
-
- // Update CRC-32[C] with a byte value according to constants in table
- void update_byte_crc32(Register crc, Register val, Register table);
-
- // Reverse byte order of lower 32 bits, assuming upper 32 bits all zeros
- void reverse_bytes_32(Register src, Register dst, Register tmp);
- void movitof_revbytes(Register src, FloatRegister dst, Register tmp1, Register tmp2);
- void movftoi_revbytes(FloatRegister src, Register dst, Register tmp1, Register tmp2);
-
- // CRC32 code for java.util.zip.CRC32::updateBytes0() intrinsic.
- void kernel_crc32(Register crc, Register buf, Register len, Register table);
- // Fold 128-bit data chunk
- void fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register buf, int offset);
- void fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register xbuf_hi, Register xbuf_lo);
- // Fold 8-bit data
- void fold_8bit_crc32(Register xcrc, Register table, Register xtmp, Register tmp);
- void fold_8bit_crc32(Register crc, Register table, Register tmp);
- // CRC32C code for java.util.zip.CRC32C::updateBytes/updateDirectByteBuffer intrinsic.
- void kernel_crc32c(Register crc, Register buf, Register len, Register table);
-
-};
-
-/**
- * class SkipIfEqual:
- *
- * Instantiating this class will result in assembly code being output that will
- * jump around any code emitted between the creation of the instance and it's
- * automatic destruction at the end of a scope block, depending on the value of
- * the flag passed to the constructor, which will be checked at run-time.
- */
-class SkipIfEqual : public StackObj {
- private:
- MacroAssembler* _masm;
- Label _label;
-
- public:
- // 'temp' is a temp register that this object can use (and trash)
- SkipIfEqual(MacroAssembler*, Register temp,
- const bool* flag_addr, Assembler::Condition condition);
- ~SkipIfEqual();
-};
-
-#endif // CPU_SPARC_MACROASSEMBLER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp
deleted file mode 100644
index c439556df63..00000000000
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_MACROASSEMBLER_SPARC_INLINE_HPP
-#define CPU_SPARC_MACROASSEMBLER_SPARC_INLINE_HPP
-
-#include "asm/assembler.inline.hpp"
-#include "asm/macroAssembler.hpp"
-#include "asm/codeBuffer.hpp"
-#include "code/codeCache.hpp"
-
-inline bool Address::is_simm13(int offset) { return Assembler::is_simm13(disp() + offset); }
-
-
-inline int AddressLiteral::low10() const {
- return Assembler::low10(value());
-}
-
-
-inline void MacroAssembler::pd_patch_instruction(address branch, address target, const char* file, int line) {
- jint& stub_inst = *(jint*) branch;
- stub_inst = patched_branch(target - branch, stub_inst, 0);
-}
-
-// Use the right loads/stores for the platform
-inline void MacroAssembler::ld_ptr( Register s1, Register s2, Register d ) {
- Assembler::ldx(s1, s2, d);
-}
-
-inline void MacroAssembler::ld_ptr( Register s1, int simm13a, Register d ) {
- Assembler::ldx(s1, simm13a, d);
-}
-
-#ifdef ASSERT
-// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-inline void MacroAssembler::ld_ptr( Register s1, ByteSize simm13a, Register d ) {
- ld_ptr(s1, in_bytes(simm13a), d);
-}
-#endif
-
-inline void MacroAssembler::ld_ptr( Register s1, RegisterOrConstant s2, Register d ) {
- ldx(s1, s2, d);
-}
-
-inline void MacroAssembler::ld_ptr(const Address& a, Register d, int offset) {
- ldx(a, d, offset);
-}
-
-inline void MacroAssembler::st_ptr( Register d, Register s1, Register s2 ) {
- Assembler::stx(d, s1, s2);
-}
-
-inline void MacroAssembler::st_ptr( Register d, Register s1, int simm13a ) {
- Assembler::stx(d, s1, simm13a);
-}
-
-#ifdef ASSERT
-// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-inline void MacroAssembler::st_ptr( Register d, Register s1, ByteSize simm13a ) {
- st_ptr(d, s1, in_bytes(simm13a));
-}
-#endif
-
-inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterOrConstant s2 ) {
- stx(d, s1, s2);
-}
-
-inline void MacroAssembler::st_ptr(Register d, const Address& a, int offset) {
- stx(d, a, offset);
-}
-
-// Use the right loads/stores for the platform
-inline void MacroAssembler::ld_long( Register s1, Register s2, Register d ) {
- Assembler::ldx(s1, s2, d);
-}
-
-inline void MacroAssembler::ld_long( Register s1, int simm13a, Register d ) {
- Assembler::ldx(s1, simm13a, d);
-}
-
-inline void MacroAssembler::ld_long( Register s1, RegisterOrConstant s2, Register d ) {
- ldx(s1, s2, d);
-}
-
-inline void MacroAssembler::ld_long(const Address& a, Register d, int offset) {
- ldx(a, d, offset);
-}
-
-inline void MacroAssembler::st_long( Register d, Register s1, Register s2 ) {
- Assembler::stx(d, s1, s2);
-}
-
-inline void MacroAssembler::st_long( Register d, Register s1, int simm13a ) {
- Assembler::stx(d, s1, simm13a);
-}
-
-inline void MacroAssembler::st_long( Register d, Register s1, RegisterOrConstant s2 ) {
- stx(d, s1, s2);
-}
-
-inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) {
- stx(d, a, offset);
-}
-
-inline void MacroAssembler::stbool(Register d, const Address& a) { stb(d, a); }
-inline void MacroAssembler::ldbool(const Address& a, Register d) { ldub(a, d); }
-inline void MacroAssembler::movbool( bool boolconst, Register d) { mov( (int) boolconst, d); }
-
-
-inline void MacroAssembler::signx( Register s, Register d ) { sra( s, G0, d); }
-inline void MacroAssembler::signx( Register d ) { sra( d, G0, d); }
-
-inline void MacroAssembler::not1( Register s, Register d ) { xnor( s, G0, d ); }
-inline void MacroAssembler::not1( Register d ) { xnor( d, G0, d ); }
-
-inline void MacroAssembler::neg( Register s, Register d ) { sub( G0, s, d ); }
-inline void MacroAssembler::neg( Register d ) { sub( G0, d, d ); }
-
-inline void MacroAssembler::cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); }
-inline void MacroAssembler::casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); }
-
-// Functions for isolating 64 bit atomic swaps for LP64
-// cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's
-inline void MacroAssembler::cas_ptr( Register s1, Register s2, Register d) {
- casx( s1, s2, d );
-}
-
-// Functions for isolating 64 bit shifts for LP64
-
-inline void MacroAssembler::sll_ptr( Register s1, Register s2, Register d ) {
- Assembler::sllx(s1, s2, d);
-}
-
-inline void MacroAssembler::sll_ptr( Register s1, int imm6a, Register d ) {
- Assembler::sllx(s1, imm6a, d);
-}
-
-inline void MacroAssembler::srl_ptr( Register s1, Register s2, Register d ) {
- Assembler::srlx(s1, s2, d);
-}
-
-inline void MacroAssembler::srl_ptr( Register s1, int imm6a, Register d ) {
- Assembler::srlx(s1, imm6a, d);
-}
-
-inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Register d ) {
- if (s2.is_register()) sll_ptr(s1, s2.as_register(), d);
- else sll_ptr(s1, s2.as_constant(), d);
-}
-
-inline void MacroAssembler::casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); }
-inline void MacroAssembler::casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); }
-
-inline void MacroAssembler::inc( Register d, int const13 ) { add( d, const13, d); }
-inline void MacroAssembler::inccc( Register d, int const13 ) { addcc( d, const13, d); }
-
-inline void MacroAssembler::dec( Register d, int const13 ) { sub( d, const13, d); }
-inline void MacroAssembler::deccc( Register d, int const13 ) { subcc( d, const13, d); }
-
-// Use the right branch for the platform
-
-inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
- Assembler::bp(c, a, icc, p, d, rt);
-}
-
-inline void MacroAssembler::br( Condition c, bool a, Predict p, Label& L ) {
- // See note[+] on 'avoid_pipeline_stall()', in "assembler_sparc.inline.hpp".
- avoid_pipeline_stall();
- br(c, a, p, target(L));
-}
-
-
-// Branch that tests either xcc or icc depending on the
-// architecture compiled (LP64 or not)
-inline void MacroAssembler::brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
- Assembler::bp(c, a, xcc, p, d, rt);
-}
-
-inline void MacroAssembler::brx( Condition c, bool a, Predict p, Label& L ) {
- avoid_pipeline_stall();
- brx(c, a, p, target(L));
-}
-
-inline void MacroAssembler::ba( Label& L ) {
- br(always, false, pt, L);
-}
-
-// Warning: V9 only functions
-inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) {
- Assembler::bp(c, a, cc, p, d, rt);
-}
-
-inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, Label& L ) {
- Assembler::bp(c, a, cc, p, L);
-}
-
-inline void MacroAssembler::fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
- fbp(c, a, fcc0, p, d, rt);
-}
-
-inline void MacroAssembler::fb( Condition c, bool a, Predict p, Label& L ) {
- avoid_pipeline_stall();
- fb(c, a, p, target(L));
-}
-
-inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) {
- Assembler::fbp(c, a, cc, p, d, rt);
-}
-
-inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, Label& L ) {
- Assembler::fbp(c, a, cc, p, L);
-}
-
-inline void MacroAssembler::jmp( Register s1, Register s2 ) { jmpl( s1, s2, G0 ); }
-inline void MacroAssembler::jmp( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, G0, rspec); }
-
-inline bool MacroAssembler::is_far_target(address d) {
- if (ForceUnreachable) {
- // References outside the code cache should be treated as far
- return d < CodeCache::low_bound() || d > CodeCache::high_bound();
- }
- return !is_in_wdisp30_range(d, CodeCache::low_bound()) || !is_in_wdisp30_range(d, CodeCache::high_bound());
-}
-
-// Call with a check to see if we need to deal with the added
-// expense of relocation and if we overflow the displacement
-// of the quick call instruction.
-inline void MacroAssembler::call( address d, relocInfo::relocType rt ) {
- MacroAssembler::call(d, Relocation::spec_simple(rt));
-}
-
-inline void MacroAssembler::call( address d, RelocationHolder const& rspec ) {
- intptr_t disp;
- // NULL is ok because it will be relocated later.
- // Must change NULL to a reachable address in order to
- // pass asserts here and in wdisp.
- if ( d == NULL )
- d = pc();
-
- // Is this address within range of the call instruction?
- // If not, use the expensive instruction sequence
- if (is_far_target(d)) {
- relocate(rspec);
- AddressLiteral dest(d);
- jumpl_to(dest, O7, O7);
- } else {
- Assembler::call(d, rspec);
- }
-}
-
-inline void MacroAssembler::call( Label& L, relocInfo::relocType rt ) {
- avoid_pipeline_stall();
- MacroAssembler::call(target(L), rt);
-}
-
-
-inline void MacroAssembler::callr( Register s1, Register s2 ) { jmpl( s1, s2, O7 ); }
-inline void MacroAssembler::callr( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, O7, rspec); }
-
-inline void MacroAssembler::tst( Register s ) { orcc( G0, s, G0 ); }
-
-inline void MacroAssembler::ret( bool trace ) {
- if (trace) {
- mov(I7, O7); // traceable register
- JMP(O7, 2 * BytesPerInstWord);
- } else {
- jmpl( I7, 2 * BytesPerInstWord, G0 );
- }
-}
-
-inline void MacroAssembler::retl( bool trace ) {
- if (trace) {
- JMP(O7, 2 * BytesPerInstWord);
- } else {
- jmpl( O7, 2 * BytesPerInstWord, G0 );
- }
-}
-
-
-inline void MacroAssembler::cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); }
-inline void MacroAssembler::cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); }
-
-// Note: All MacroAssembler::set_foo functions are defined out-of-line.
-
-
-// Loads the current PC of the following instruction as an immediate value in
-// 2 instructions. All PCs in the CodeCache are within 2 Gig of each other.
-inline intptr_t MacroAssembler::load_pc_address( Register reg, int bytes_to_skip ) {
- intptr_t thepc = (intptr_t)pc() + 2*BytesPerInstWord + bytes_to_skip;
- Unimplemented();
- return thepc;
-}
-
-
-inline void MacroAssembler::load_contents(const AddressLiteral& addrlit, Register d, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, d);
- } else {
- sethi(addrlit, d);
- }
- ld(d, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::load_bool_contents(const AddressLiteral& addrlit, Register d, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, d);
- } else {
- sethi(addrlit, d);
- }
- ldub(d, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, d);
- } else {
- sethi(addrlit, d);
- }
- ld_ptr(d, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, temp);
- } else {
- sethi(addrlit, temp);
- }
- st(s, temp, addrlit.low10() + offset);
-}
-
-
-inline void MacroAssembler::store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, temp);
- } else {
- sethi(addrlit, temp);
- }
- st_ptr(s, temp, addrlit.low10() + offset);
-}
-
-
-// This code sequence is relocatable to any address, even on LP64.
-inline void MacroAssembler::jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset) {
- assert_not_delayed();
- // Force fixed length sethi because NativeJump and NativeFarCall don't handle
- // variable length instruction streams.
- patchable_sethi(addrlit, temp);
- jmpl(temp, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::jump_to(const AddressLiteral& addrlit, Register temp, int offset) {
- jumpl_to(addrlit, temp, G0, offset);
-}
-
-
-inline void MacroAssembler::jump_indirect_to(Address& a, Register temp,
- int ld_offset, int jmp_offset) {
- assert_not_delayed();
- //sethi(al); // sethi is caller responsibility for this one
- ld_ptr(a, temp, ld_offset);
- jmp(temp, jmp_offset);
-}
-
-
-inline void MacroAssembler::set_metadata(Metadata* obj, Register d) {
- set_metadata(allocate_metadata_address(obj), d);
-}
-
-inline void MacroAssembler::set_metadata_constant(Metadata* obj, Register d) {
- set_metadata(constant_metadata_address(obj), d);
-}
-
-inline void MacroAssembler::set_metadata(const AddressLiteral& obj_addr, Register d) {
- assert(obj_addr.rspec().type() == relocInfo::metadata_type, "must be a metadata reloc");
- set(obj_addr, d);
-}
-
-inline void MacroAssembler::set_oop(jobject obj, Register d) {
- set_oop(allocate_oop_address(obj), d);
-}
-
-
-inline void MacroAssembler::set_oop_constant(jobject obj, Register d) {
- set_oop(constant_oop_address(obj), d);
-}
-
-
-inline void MacroAssembler::set_oop(const AddressLiteral& obj_addr, Register d) {
- assert(obj_addr.rspec().type() == relocInfo::oop_type, "must be an oop reloc");
- set(obj_addr, d);
-}
-
-
-inline void MacroAssembler::load_argument( Argument& a, Register d ) {
- if (a.is_register())
- mov(a.as_register(), d);
- else
- ld (a.as_address(), d);
-}
-
-inline void MacroAssembler::store_argument( Register s, Argument& a ) {
- if (a.is_register())
- mov(s, a.as_register());
- else
- st_ptr (s, a.as_address()); // ABI says everything is right justified.
-}
-
-inline void MacroAssembler::store_ptr_argument( Register s, Argument& a ) {
- if (a.is_register())
- mov(s, a.as_register());
- else
- st_ptr (s, a.as_address());
-}
-
-
-inline void MacroAssembler::store_float_argument( FloatRegister s, Argument& a ) {
- if (a.is_float_register())
-// V9 ABI has F1, F3, F5 are used to pass instead of O0, O1, O2
- fmov(FloatRegisterImpl::S, s, a.as_float_register() );
- else
- // Floats are stored in the high half of the stack entry
- // The low half is undefined per the ABI.
- stf(FloatRegisterImpl::S, s, a.as_address(), sizeof(jfloat));
-}
-
-inline void MacroAssembler::store_double_argument( FloatRegister s, Argument& a ) {
- if (a.is_float_register())
-// V9 ABI has D0, D2, D4 are used to pass instead of O0, O1, O2
- fmov(FloatRegisterImpl::D, s, a.as_double_register() );
- else
- stf(FloatRegisterImpl::D, s, a.as_address());
-}
-
-inline void MacroAssembler::store_long_argument( Register s, Argument& a ) {
- if (a.is_register())
- mov(s, a.as_register());
- else
- stx(s, a.as_address());
-}
-
-inline void MacroAssembler::round_to( Register r, int modulus ) {
- assert_not_delayed();
- inc( r, modulus - 1 );
- and3( r, -modulus, r );
-}
-
-inline void MacroAssembler::add(Register s1, int simm13a, Register d, relocInfo::relocType rtype) {
- relocate(rtype);
- add(s1, simm13a, d);
-}
-inline void MacroAssembler::add(Register s1, int simm13a, Register d, RelocationHolder const& rspec) {
- relocate(rspec);
- add(s1, simm13a, d);
-}
-
-// form effective addresses this way:
-inline void MacroAssembler::add(const Address& a, Register d, int offset) {
- if (a.has_index()) add(a.base(), a.index(), d);
- else { add(a.base(), a.disp() + offset, d, a.rspec(offset)); offset = 0; }
- if (offset != 0) add(d, offset, d);
-}
-inline void MacroAssembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) {
- if (s2.is_register()) add(s1, s2.as_register(), d);
- else { add(s1, s2.as_constant() + offset, d); offset = 0; }
- if (offset != 0) add(d, offset, d);
-}
-
-inline void MacroAssembler::andn(Register s1, RegisterOrConstant s2, Register d) {
- if (s2.is_register()) andn(s1, s2.as_register(), d);
- else andn(s1, s2.as_constant(), d);
-}
-
-inline void MacroAssembler::btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); }
-inline void MacroAssembler::btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); }
-
-inline void MacroAssembler::bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); }
-inline void MacroAssembler::bset( int simm13a, Register s ) { or3( s, simm13a, s ); }
-
-inline void MacroAssembler::bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); }
-inline void MacroAssembler::bclr( int simm13a, Register s ) { andn( s, simm13a, s ); }
-
-inline void MacroAssembler::btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); }
-inline void MacroAssembler::btog( int simm13a, Register s ) { xor3( s, simm13a, s ); }
-
-inline void MacroAssembler::clr( Register d ) { or3( G0, G0, d ); }
-
-inline void MacroAssembler::clrb( Register s1, Register s2) { stb( G0, s1, s2 ); }
-inline void MacroAssembler::clrh( Register s1, Register s2) { sth( G0, s1, s2 ); }
-inline void MacroAssembler::clr( Register s1, Register s2) { stw( G0, s1, s2 ); }
-inline void MacroAssembler::clrx( Register s1, Register s2) { stx( G0, s1, s2 ); }
-
-inline void MacroAssembler::clrb( Register s1, int simm13a) { stb( G0, s1, simm13a); }
-inline void MacroAssembler::clrh( Register s1, int simm13a) { sth( G0, s1, simm13a); }
-inline void MacroAssembler::clr( Register s1, int simm13a) { stw( G0, s1, simm13a); }
-inline void MacroAssembler::clrx( Register s1, int simm13a) { stx( G0, s1, simm13a); }
-
-inline void MacroAssembler::clruw( Register s, Register d ) { srl( s, G0, d); }
-inline void MacroAssembler::clruwu( Register d ) { srl( d, G0, d); }
-
-// Make all 32 bit loads signed so 64 bit registers maintain proper sign
-inline void MacroAssembler::ld( Register s1, Register s2, Register d) { ldsw( s1, s2, d); }
-inline void MacroAssembler::ld( Register s1, int simm13a, Register d) { ldsw( s1, simm13a, d); }
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-inline void MacroAssembler::ld(Register s1, ByteSize simm13a, Register d) { ldsw( s1, in_bytes(simm13a), d); }
-#endif
-
-inline void MacroAssembler::ld( const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ld( a.base(), a.index(), d); }
- else { ld( a.base(), a.disp() + offset, d); }
-}
-
-inline void MacroAssembler::ldsb(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldsb(a.base(), a.index(), d); }
- else { ldsb(a.base(), a.disp() + offset, d); }
-}
-inline void MacroAssembler::ldsh(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldsh(a.base(), a.index(), d); }
- else { ldsh(a.base(), a.disp() + offset, d); }
-}
-inline void MacroAssembler::ldsw(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldsw(a.base(), a.index(), d); }
- else { ldsw(a.base(), a.disp() + offset, d); }
-}
-inline void MacroAssembler::ldub(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldub(a.base(), a.index(), d); }
- else { ldub(a.base(), a.disp() + offset, d); }
-}
-inline void MacroAssembler::lduh(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); lduh(a.base(), a.index(), d); }
- else { lduh(a.base(), a.disp() + offset, d); }
-}
-inline void MacroAssembler::lduw(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); lduw(a.base(), a.index(), d); }
- else { lduw(a.base(), a.disp() + offset, d); }
-}
-inline void MacroAssembler::ldd( const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldd( a.base(), a.index(), d); }
- else { ldd( a.base(), a.disp() + offset, d); }
-}
-inline void MacroAssembler::ldx( const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldx( a.base(), a.index(), d); }
- else { ldx( a.base(), a.disp() + offset, d); }
-}
-
-inline void MacroAssembler::ldub(Register s1, RegisterOrConstant s2, Register d) { ldub(Address(s1, s2), d); }
-inline void MacroAssembler::ldsb(Register s1, RegisterOrConstant s2, Register d) { ldsb(Address(s1, s2), d); }
-inline void MacroAssembler::lduh(Register s1, RegisterOrConstant s2, Register d) { lduh(Address(s1, s2), d); }
-inline void MacroAssembler::ldsh(Register s1, RegisterOrConstant s2, Register d) { ldsh(Address(s1, s2), d); }
-inline void MacroAssembler::lduw(Register s1, RegisterOrConstant s2, Register d) { lduw(Address(s1, s2), d); }
-inline void MacroAssembler::ldsw(Register s1, RegisterOrConstant s2, Register d) { ldsw(Address(s1, s2), d); }
-inline void MacroAssembler::ldx( Register s1, RegisterOrConstant s2, Register d) { ldx( Address(s1, s2), d); }
-inline void MacroAssembler::ld( Register s1, RegisterOrConstant s2, Register d) { ld( Address(s1, s2), d); }
-inline void MacroAssembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); }
-
-inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d) {
- if (s2.is_register()) ldf(w, s1, s2.as_register(), d);
- else ldf(w, s1, s2.as_constant(), d);
-}
-
-inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset) {
- relocate(a.rspec(offset));
- if (a.has_index()) {
- assert(offset == 0, "");
- ldf(w, a.base(), a.index(), d);
- } else {
- ldf(w, a.base(), a.disp() + offset, d);
- }
-}
-
-inline void MacroAssembler::lduwl(Register s1, Register s2, Register d) { lduwa(s1, s2, ASI_PRIMARY_LITTLE, d); }
-inline void MacroAssembler::ldswl(Register s1, Register s2, Register d) { ldswa(s1, s2, ASI_PRIMARY_LITTLE, d);}
-inline void MacroAssembler::ldxl( Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); }
-inline void MacroAssembler::ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); }
-
-// returns if membar generates anything, obviously this code should mirror
-// membar below.
-inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) {
- const Membar_mask_bits effective_mask =
- Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
- return (effective_mask != 0);
-}
-
-inline void MacroAssembler::membar( Membar_mask_bits const7a ) {
- // Weakened for current Sparcs and TSO. See the v9 manual, sections 8.4.3,
- // 8.4.4.3, a.31 and a.50.
- // Under TSO, setting bit 3, 2, or 0 is redundant, so the only value
- // of the mmask subfield of const7a that does anything that isn't done
- // implicitly is StoreLoad.
- const Membar_mask_bits effective_mask =
- Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
- if (effective_mask != 0) {
- Assembler::membar(effective_mask);
- }
-}
-
-inline void MacroAssembler::mov(Register s, Register d) {
- if (s != d) {
- or3(G0, s, d);
- } else {
- assert_not_delayed(); // Put something useful in the delay slot!
- }
-}
-
-inline void MacroAssembler::mov_or_nop(Register s, Register d) {
- if (s != d) {
- or3(G0, s, d);
- } else {
- nop();
- }
-}
-
-inline void MacroAssembler::mov( int simm13a, Register d) { or3( G0, simm13a, d); }
-
-inline void MacroAssembler::prefetch(const Address& a, PrefetchFcn f, int offset) {
- relocate(a.rspec(offset));
- assert(!a.has_index(), "");
- prefetch(a.base(), a.disp() + offset, f);
-}
-
-inline void MacroAssembler::st(Register d, Register s1, Register s2) { stw(d, s1, s2); }
-inline void MacroAssembler::st(Register d, Register s1, int simm13a) { stw(d, s1, simm13a); }
-
-#ifdef ASSERT
-// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-inline void MacroAssembler::st(Register d, Register s1, ByteSize simm13a) { stw(d, s1, in_bytes(simm13a)); }
-#endif
-
-inline void MacroAssembler::st(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); st( d, a.base(), a.index() ); }
- else { st( d, a.base(), a.disp() + offset); }
-}
-
-inline void MacroAssembler::stb(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); stb(d, a.base(), a.index() ); }
- else { stb(d, a.base(), a.disp() + offset); }
-}
-inline void MacroAssembler::sth(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); sth(d, a.base(), a.index() ); }
- else { sth(d, a.base(), a.disp() + offset); }
-}
-inline void MacroAssembler::stw(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); stw(d, a.base(), a.index() ); }
- else { stw(d, a.base(), a.disp() + offset); }
-}
-inline void MacroAssembler::std(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); std(d, a.base(), a.index() ); }
- else { std(d, a.base(), a.disp() + offset); }
-}
-inline void MacroAssembler::stx(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); stx(d, a.base(), a.index() ); }
- else { stx(d, a.base(), a.disp() + offset); }
-}
-
-inline void MacroAssembler::stb(Register d, Register s1, RegisterOrConstant s2) { stb(d, Address(s1, s2)); }
-inline void MacroAssembler::sth(Register d, Register s1, RegisterOrConstant s2) { sth(d, Address(s1, s2)); }
-inline void MacroAssembler::stw(Register d, Register s1, RegisterOrConstant s2) { stw(d, Address(s1, s2)); }
-inline void MacroAssembler::stx(Register d, Register s1, RegisterOrConstant s2) { stx(d, Address(s1, s2)); }
-inline void MacroAssembler::std(Register d, Register s1, RegisterOrConstant s2) { std(d, Address(s1, s2)); }
-inline void MacroAssembler::st( Register d, Register s1, RegisterOrConstant s2) { st( d, Address(s1, s2)); }
-
-inline void MacroAssembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2) {
- if (s2.is_register()) stf(w, d, s1, s2.as_register());
- else stf(w, d, s1, s2.as_constant());
-}
-
-inline void MacroAssembler::stf(FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset) {
- relocate(a.rspec(offset));
- if (a.has_index()) { assert(offset == 0, ""); stf(w, d, a.base(), a.index() ); }
- else { stf(w, d, a.base(), a.disp() + offset); }
-}
-
-inline void MacroAssembler::sub(Register s1, RegisterOrConstant s2, Register d, int offset) {
- if (s2.is_register()) sub(s1, s2.as_register(), d);
- else { sub(s1, s2.as_constant() + offset, d); offset = 0; }
- if (offset != 0) sub(d, offset, d);
-}
-
-inline void MacroAssembler::swap(const Address& a, Register d, int offset) {
- relocate(a.rspec(offset));
- if (a.has_index()) { assert(offset == 0, ""); swap(a.base(), a.index(), d ); }
- else { swap(a.base(), a.disp() + offset, d); }
-}
-#endif // CPU_SPARC_MACROASSEMBLER_SPARC_INLINE_HPP
diff --git a/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp b/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp
deleted file mode 100644
index 9e1674592ab..00000000000
--- a/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/memset_with_concurrent_readers.hpp"
-#include "runtime/prefetch.inline.hpp"
-#include "utilities/align.hpp"
-#include "utilities/debug.hpp"
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
-
-// An implementation of memset, for use when there may be concurrent
-// readers of the region being stored into.
-//
-// We can't use the standard library memset if it is implemented using
-// block initializing stores. Doing so can result in concurrent readers
-// seeing spurious zeros.
-//
-// We can't use the obvious C/C++ for-loop, because the compiler may
-// recognize the idiomatic loop and optimize it into a call to the
-// standard library memset; we've seen exactly this happen with, for
-// example, Solaris Studio 12.3. Hence the use of inline assembly
-// code, hiding loops from the compiler's optimizer.
-//
-// We don't attempt to use the standard library memset when it is safe
-// to do so. We could conservatively do so by detecting the presence
-// of block initializing stores (VM_Version::has_blk_init()), but the
-// implementation provided here should be sufficient.
-
-inline void fill_subword(void* start, void* end, int value) {
- STATIC_ASSERT(BytesPerWord == 8);
- assert(pointer_delta(end, start, 1) < (size_t)BytesPerWord, "precondition");
- // Dispatch on (end - start).
- void* pc;
- __asm__ volatile(
- // offset := (7 - (end - start)) + 3
- // 3 instructions from rdpc to DISPATCH
- " sub %[offset], %[end], %[offset]\n\t" // offset := start - end
- " sllx %[offset], 2, %[offset]\n\t" // scale offset for instruction size of 4
- " add %[offset], 40, %[offset]\n\t" // offset += 10 * instruction size
- " rd %%pc, %[pc]\n\t" // dispatch on scaled offset
- " jmpl %[pc]+%[offset], %%g0\n\t"
- " nop\n\t"
- // DISPATCH: no direct reference, but without it the store block may be elided.
- "1:\n\t"
- " stb %[value], [%[end]-7]\n\t" // end[-7] = value
- " stb %[value], [%[end]-6]\n\t"
- " stb %[value], [%[end]-5]\n\t"
- " stb %[value], [%[end]-4]\n\t"
- " stb %[value], [%[end]-3]\n\t"
- " stb %[value], [%[end]-2]\n\t"
- " stb %[value], [%[end]-1]\n\t" // end[-1] = value
- : /* only temporaries/overwritten outputs */
- [pc] "=&r" (pc), // temp
- [offset] "+&r" (start)
- : [end] "r" (end),
- [value] "r" (value)
- : "memory");
-}
-
-void memset_with_concurrent_readers(void* to, int value, size_t size) {
- Prefetch::write(to, 0);
- void* end = static_cast(to) + size;
- if (size >= (size_t)BytesPerWord) {
- // Fill any partial word prefix.
- uintx* aligned_to = static_cast(align_up(to, BytesPerWord));
- fill_subword(to, aligned_to, value);
-
- // Compute fill word.
- STATIC_ASSERT(BitsPerByte == 8);
- STATIC_ASSERT(BitsPerWord == 64);
- uintx xvalue = value & 0xff;
- xvalue |= (xvalue << 8);
- xvalue |= (xvalue << 16);
- xvalue |= (xvalue << 32);
-
- uintx* aligned_end = static_cast(align_down(end, BytesPerWord));
- assert(aligned_to <= aligned_end, "invariant");
-
- // for ( ; aligned_to < aligned_end; ++aligned_to) {
- // *aligned_to = xvalue;
- // }
- uintptr_t temp;
- __asm__ volatile(
- // Unroll loop x8.
- " sub %[aend], %[ato], %[temp]\n\t"
- " cmp %[temp], 56\n\t" // cc := (aligned_end - aligned_to) > 7 words
- " ba %%xcc, 2f\n\t" // goto TEST always
- " sub %[aend], 56, %[temp]\n\t" // limit := aligned_end - 7 words
- // LOOP:
- "1:\n\t" // unrolled x8 store loop top
- " cmp %[temp], %[ato]\n\t" // cc := limit > (next) aligned_to
- " stx %[xvalue], [%[ato]-64]\n\t" // store 8 words, aligned_to pre-incremented
- " stx %[xvalue], [%[ato]-56]\n\t"
- " stx %[xvalue], [%[ato]-48]\n\t"
- " stx %[xvalue], [%[ato]-40]\n\t"
- " stx %[xvalue], [%[ato]-32]\n\t"
- " stx %[xvalue], [%[ato]-24]\n\t"
- " stx %[xvalue], [%[ato]-16]\n\t"
- " stx %[xvalue], [%[ato]-8]\n\t"
- // TEST:
- "2:\n\t"
- " bgu,a %%xcc, 1b\n\t" // goto LOOP if more than 7 words remaining
- " add %[ato], 64, %[ato]\n\t" // aligned_to += 8, for next iteration
- // Fill remaining < 8 full words.
- // Dispatch on (aligned_end - aligned_to).
- // offset := (7 - (aligned_end - aligned_to)) + 3
- // 3 instructions from rdpc to DISPATCH
- " sub %[ato], %[aend], %[ato]\n\t" // offset := aligned_to - aligned_end
- " srax %[ato], 1, %[ato]\n\t" // scale offset for instruction size of 4
- " add %[ato], 40, %[ato]\n\t" // offset += 10 * instruction size
- " rd %%pc, %[temp]\n\t" // dispatch on scaled offset
- " jmpl %[temp]+%[ato], %%g0\n\t"
- " nop\n\t"
- // DISPATCH: no direct reference, but without it the store block may be elided.
- "3:\n\t"
- " stx %[xvalue], [%[aend]-56]\n\t" // aligned_end[-7] = xvalue
- " stx %[xvalue], [%[aend]-48]\n\t"
- " stx %[xvalue], [%[aend]-40]\n\t"
- " stx %[xvalue], [%[aend]-32]\n\t"
- " stx %[xvalue], [%[aend]-24]\n\t"
- " stx %[xvalue], [%[aend]-16]\n\t"
- " stx %[xvalue], [%[aend]-8]\n\t" // aligned_end[-1] = xvalue
- : /* only temporaries/overwritten outputs */
- [temp] "=&r" (temp),
- [ato] "+&r" (aligned_to)
- : [aend] "r" (aligned_end),
- [xvalue] "r" (xvalue)
- : "cc", "memory");
- to = aligned_end; // setup for suffix
- }
- // Fill any partial word suffix. Also the prefix if size < BytesPerWord.
- fill_subword(to, end, value);
-}
diff --git a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp
deleted file mode 100644
index d13801665ef..00000000000
--- a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "jvm.h"
-#include "asm/macroAssembler.inline.hpp"
-#include "classfile/javaClasses.inline.hpp"
-#include "interpreter/interpreter.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "logging/log.hpp"
-#include "memory/allocation.inline.hpp"
-#include "memory/resourceArea.hpp"
-#include "prims/methodHandles.hpp"
-#include "runtime/flags/flagSetting.hpp"
-#include "runtime/frame.inline.hpp"
-#include "utilities/preserveException.hpp"
-
-#define __ _masm->
-
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) /* nothing */
-#define STOP(error) stop(error)
-#else
-#define BLOCK_COMMENT(str) __ block_comment(str)
-#define STOP(error) block_comment(error); __ stop(error)
-#endif
-
-#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
-
-// Workaround for C++ overloading nastiness on '0' for RegisterOrConstant.
-static RegisterOrConstant constant(int value) {
- return RegisterOrConstant(value);
-}
-
-void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp_reg, Register temp2_reg) {
- if (VerifyMethodHandles)
- verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class), temp_reg, temp2_reg,
- "MH argument is a Class");
- __ ld_ptr(Address(klass_reg, java_lang_Class::klass_offset_in_bytes()), klass_reg);
-}
-
-#ifdef ASSERT
-static int check_nonzero(const char* xname, int x) {
- assert(x != 0, "%s should be nonzero", xname);
- return x;
-}
-#define NONZERO(x) check_nonzero(#x, x)
-#else //ASSERT
-#define NONZERO(x) (x)
-#endif //ASSERT
-
-#ifdef ASSERT
-void MethodHandles::verify_klass(MacroAssembler* _masm,
- Register obj_reg, SystemDictionary::WKID klass_id,
- Register temp_reg, Register temp2_reg,
- const char* error_message) {
- InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
- Klass* klass = SystemDictionary::well_known_klass(klass_id);
- bool did_save = false;
- if (temp_reg == noreg || temp2_reg == noreg) {
- temp_reg = L1;
- temp2_reg = L2;
- __ save_frame_and_mov(0, obj_reg, L0);
- obj_reg = L0;
- did_save = true;
- }
- Label L_ok, L_bad;
- BLOCK_COMMENT("verify_klass {");
- __ verify_oop(obj_reg);
- __ br_null_short(obj_reg, Assembler::pn, L_bad);
- __ load_klass(obj_reg, temp_reg);
- __ set(ExternalAddress((Metadata**)klass_addr), temp2_reg);
- __ ld_ptr(Address(temp2_reg, 0), temp2_reg);
- __ cmp_and_brx_short(temp_reg, temp2_reg, Assembler::equal, Assembler::pt, L_ok);
- intptr_t super_check_offset = klass->super_check_offset();
- __ ld_ptr(Address(temp_reg, super_check_offset), temp_reg);
- __ set(ExternalAddress((Metadata**)klass_addr), temp2_reg);
- __ ld_ptr(Address(temp2_reg, 0), temp2_reg);
- __ cmp_and_brx_short(temp_reg, temp2_reg, Assembler::equal, Assembler::pt, L_ok);
- __ BIND(L_bad);
- if (did_save) __ restore();
- __ STOP(error_message);
- __ BIND(L_ok);
- if (did_save) __ restore();
- BLOCK_COMMENT("} verify_klass");
-}
-
-void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) {
- Label L;
- BLOCK_COMMENT("verify_ref_kind {");
- __ lduw(Address(member_reg, NONZERO(java_lang_invoke_MemberName::flags_offset_in_bytes())), temp);
- __ srl( temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT, temp);
- __ and3(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK, temp);
- __ cmp_and_br_short(temp, ref_kind, Assembler::equal, Assembler::pt, L);
- { char* buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal);
- jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind);
- if (ref_kind == JVM_REF_invokeVirtual ||
- ref_kind == JVM_REF_invokeSpecial)
- // could do this for all ref_kinds, but would explode assembly code size
- trace_method_handle(_masm, buf);
- __ STOP(buf);
- }
- BLOCK_COMMENT("} verify_ref_kind");
- __ bind(L);
-}
-
-#endif // ASSERT
-
-void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp,
- bool for_compiler_entry) {
- Label L_no_such_method;
- assert(method == G5_method, "interpreter calling convention");
- assert_different_registers(method, target, temp);
-
- if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
- Label run_compiled_code;
- // JVMTI events, such as single-stepping, are implemented partly by avoiding running
- // compiled code in threads for which the event is enabled. Check here for
- // interp_only_mode if these events CAN be enabled.
- __ verify_thread();
- const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset());
- __ ld(interp_only, temp);
- __ cmp_and_br_short(temp, 0, Assembler::zero, Assembler::pt, run_compiled_code);
- // Null method test is replicated below in compiled case,
- // it might be able to address across the verify_thread()
- __ br_null_short(G5_method, Assembler::pn, L_no_such_method);
- __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), target);
- __ jmp(target, 0);
- __ delayed()->nop();
- __ BIND(run_compiled_code);
- // Note: we could fill some delay slots here, but
- // it doesn't matter, since this is interpreter code.
- }
-
- // Compiled case, either static or fall-through from runtime conditional
- __ br_null_short(G5_method, Assembler::pn, L_no_such_method);
-
- const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() :
- Method::from_interpreted_offset();
- __ ld_ptr(G5_method, in_bytes(entry_offset), target);
- __ jmp(target, 0);
- __ delayed()->nop();
-
- __ bind(L_no_such_method);
- AddressLiteral ame(StubRoutines::throw_AbstractMethodError_entry());
- __ jump_to(ame, temp);
- __ delayed()->nop();
-}
-
-void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
- Register recv, Register method_temp,
- Register temp2, Register temp3,
- bool for_compiler_entry) {
- BLOCK_COMMENT("jump_to_lambda_form {");
- // This is the initial entry point of a lazy method handle.
- // After type checking, it picks up the invoker from the LambdaForm.
- assert_different_registers(recv, method_temp, temp2); // temp3 is only passed on
- assert(method_temp == G5_method, "required register for loading method");
-
- //NOT_PRODUCT({ FlagSetting fs(TraceMethodHandles, true); trace_method_handle(_masm, "LZMH"); });
-
- // Load the invoker, as MH -> MH.form -> LF.vmentry
- __ verify_oop(recv);
- __ load_heap_oop(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), method_temp, temp2);
- __ verify_oop(method_temp);
- __ load_heap_oop(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2);
- __ verify_oop(method_temp);
- __ load_heap_oop(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()), method_temp, temp2);
- __ verify_oop(method_temp);
- __ ld_ptr(Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())), method_temp);
-
- if (VerifyMethodHandles && !for_compiler_entry) {
- // make sure recv is already on stack
- __ ld_ptr(method_temp, in_bytes(Method::const_offset()), temp2);
- __ load_sized_value(Address(temp2, ConstMethod::size_of_parameters_offset()),
- temp2,
- sizeof(u2), /*is_signed*/ false);
- // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
- Label L;
- __ ld_ptr(__ argument_address(temp2, temp2, -1), temp2);
- __ cmp_and_br_short(temp2, recv, Assembler::equal, Assembler::pt, L);
- __ STOP("receiver not on stack");
- __ BIND(L);
- }
-
- jump_from_method_handle(_masm, method_temp, temp2, temp3, for_compiler_entry);
- BLOCK_COMMENT("} jump_to_lambda_form");
-}
-
-
-// Code generation
-address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
- vmIntrinsics::ID iid) {
- const bool not_for_compiler_entry = false; // this is the interpreter entry
- assert(is_signature_polymorphic(iid), "expected invoke iid");
- if (iid == vmIntrinsics::_invokeGeneric ||
- iid == vmIntrinsics::_compiledLambdaForm) {
- // Perhaps surprisingly, the symbolic references visible to Java are not directly used.
- // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod.
- // They all allow an appendix argument.
- __ should_not_reach_here(); // empty stubs make SG sick
- return NULL;
- }
-
- // I5_savedSP/O5_savedSP: sender SP (must preserve; see prepare_to_jump_from_interpreted)
- // G5_method: Method*
- // G4 (Gargs): incoming argument list (must preserve)
- // O0: used as temp to hold mh or receiver
- // O1, O4: garbage temps, blown away
- Register O1_scratch = O1;
- Register O4_param_size = O4; // size of parameters
-
- // here's where control starts out:
- __ align(CodeEntryAlignment);
- address entry_point = __ pc();
-
- if (VerifyMethodHandles) {
- assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2");
-
- Label L;
- BLOCK_COMMENT("verify_intrinsic_id {");
- __ lduh(Address(G5_method, Method::intrinsic_id_offset_in_bytes()), O1_scratch);
- __ cmp_and_br_short(O1_scratch, (int) iid, Assembler::equal, Assembler::pt, L);
- if (iid == vmIntrinsics::_linkToVirtual ||
- iid == vmIntrinsics::_linkToSpecial) {
- // could do this for all kinds, but would explode assembly code size
- trace_method_handle(_masm, "bad Method*::intrinsic_id");
- }
- __ STOP("bad Method*::intrinsic_id");
- __ bind(L);
- BLOCK_COMMENT("} verify_intrinsic_id");
- }
-
- // First task: Find out how big the argument list is.
- Address O4_first_arg_addr;
- int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid);
- assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic");
- if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) {
- __ ld_ptr(G5_method, in_bytes(Method::const_offset()), O4_param_size);
- __ load_sized_value(Address(O4_param_size, ConstMethod::size_of_parameters_offset()),
- O4_param_size,
- sizeof(u2), /*is_signed*/ false);
- // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
- O4_first_arg_addr = __ argument_address(O4_param_size, O4_param_size, -1);
- } else {
- DEBUG_ONLY(O4_param_size = noreg);
- }
-
- Register O0_mh = noreg;
- if (!is_signature_polymorphic_static(iid)) {
- __ ld_ptr(O4_first_arg_addr, O0_mh = O0);
- DEBUG_ONLY(O4_param_size = noreg);
- }
-
- // O4_first_arg_addr is live!
-
- if (log_is_enabled(Info, methodhandles)) {
- if (O0_mh != noreg)
- __ mov(O0_mh, G3_method_handle); // make stub happy
- trace_method_handle_interpreter_entry(_masm, iid);
- }
-
- if (iid == vmIntrinsics::_invokeBasic) {
- generate_method_handle_dispatch(_masm, iid, O0_mh, noreg, not_for_compiler_entry);
-
- } else {
- // Adjust argument list by popping the trailing MemberName argument.
- Register O0_recv = noreg;
- if (MethodHandles::ref_kind_has_receiver(ref_kind)) {
- // Load the receiver (not the MH; the actual MemberName's receiver) up from the interpreter stack.
- __ ld_ptr(O4_first_arg_addr, O0_recv = O0);
- DEBUG_ONLY(O4_param_size = noreg);
- }
- Register G5_member = G5_method; // MemberName ptr; incoming method ptr is dead now
- __ ld_ptr(__ argument_address(constant(0)), G5_member);
- __ add(Gargs, Interpreter::stackElementSize, Gargs);
- generate_method_handle_dispatch(_masm, iid, O0_recv, G5_member, not_for_compiler_entry);
- }
-
- return entry_point;
-}
-
-void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
- vmIntrinsics::ID iid,
- Register receiver_reg,
- Register member_reg,
- bool for_compiler_entry) {
- assert(is_signature_polymorphic(iid), "expected invoke iid");
- Register temp1 = (for_compiler_entry ? G1_scratch : O1);
- Register temp2 = (for_compiler_entry ? G3_scratch : O2);
- Register temp3 = (for_compiler_entry ? G4_scratch : O3);
- Register temp4 = (for_compiler_entry ? noreg : O4);
- if (for_compiler_entry) {
- assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : O0), "only valid assignment");
- assert_different_registers(temp1, O0, O1, O2, O3, O4, O5);
- assert_different_registers(temp2, O0, O1, O2, O3, O4, O5);
- assert_different_registers(temp3, O0, O1, O2, O3, O4, O5);
- assert_different_registers(temp4, O0, O1, O2, O3, O4, O5);
- } else {
- assert_different_registers(temp1, temp2, temp3, temp4, O5_savedSP); // don't trash lastSP
- }
- if (receiver_reg != noreg) assert_different_registers(temp1, temp2, temp3, temp4, receiver_reg);
- if (member_reg != noreg) assert_different_registers(temp1, temp2, temp3, temp4, member_reg);
-
- if (iid == vmIntrinsics::_invokeBasic) {
- // indirect through MH.form.vmentry.vmtarget
- jump_to_lambda_form(_masm, receiver_reg, G5_method, temp1, temp2, for_compiler_entry);
-
- } else {
- // The method is a member invoker used by direct method handles.
- if (VerifyMethodHandles) {
- // make sure the trailing argument really is a MemberName (caller responsibility)
- verify_klass(_masm, member_reg, SystemDictionary::WK_KLASS_ENUM_NAME(MemberName_klass),
- temp1, temp2,
- "MemberName required for invokeVirtual etc.");
- }
-
- Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()));
- Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes()));
- Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()));
- Address vmtarget_method( G5_method, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes()));
-
- Register temp1_recv_klass = temp1;
- if (iid != vmIntrinsics::_linkToStatic) {
- __ verify_oop(receiver_reg);
- if (iid == vmIntrinsics::_linkToSpecial) {
- // Don't actually load the klass; just null-check the receiver.
- __ null_check(receiver_reg);
- } else {
- // load receiver klass itself
- __ null_check(receiver_reg, oopDesc::klass_offset_in_bytes());
- __ load_klass(receiver_reg, temp1_recv_klass);
- __ verify_klass_ptr(temp1_recv_klass);
- }
- BLOCK_COMMENT("check_receiver {");
- // The receiver for the MemberName must be in receiver_reg.
- // Check the receiver against the MemberName.clazz
- if (VerifyMethodHandles && iid == vmIntrinsics::_linkToSpecial) {
- // Did not load it above...
- __ load_klass(receiver_reg, temp1_recv_klass);
- __ verify_klass_ptr(temp1_recv_klass);
- }
- if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) {
- Label L_ok;
- Register temp2_defc = temp2;
- __ load_heap_oop(member_clazz, temp2_defc, temp3);
- load_klass_from_Class(_masm, temp2_defc, temp3, temp4);
- __ verify_klass_ptr(temp2_defc);
- __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, L_ok);
- // If we get here, the type check failed!
- __ STOP("receiver class disagrees with MemberName.clazz");
- __ bind(L_ok);
- }
- BLOCK_COMMENT("} check_receiver");
- }
- if (iid == vmIntrinsics::_linkToSpecial ||
- iid == vmIntrinsics::_linkToStatic) {
- DEBUG_ONLY(temp1_recv_klass = noreg); // these guys didn't load the recv_klass
- }
-
- // Live registers at this point:
- // member_reg - MemberName that was the trailing argument
- // temp1_recv_klass - klass of stacked receiver, if needed
- // O5_savedSP - interpreter linkage (if interpreted)
- // O0..O5 - compiler arguments (if compiled)
-
- Label L_incompatible_class_change_error;
- switch (iid) {
- case vmIntrinsics::_linkToSpecial:
- if (VerifyMethodHandles) {
- verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp2);
- }
- __ load_heap_oop(member_vmtarget, G5_method, temp3);
- __ ld_ptr(vmtarget_method, G5_method);
- break;
-
- case vmIntrinsics::_linkToStatic:
- if (VerifyMethodHandles) {
- verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp2);
- }
- __ load_heap_oop(member_vmtarget, G5_method, temp3);
- __ ld_ptr(vmtarget_method, G5_method);
- break;
-
- case vmIntrinsics::_linkToVirtual:
- {
- // same as TemplateTable::invokevirtual,
- // minus the CP setup and profiling:
-
- if (VerifyMethodHandles) {
- verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp2);
- }
-
- // pick out the vtable index from the MemberName, and then we can discard it:
- Register temp2_index = temp2;
- __ ld_ptr(member_vmindex, temp2_index);
-
- if (VerifyMethodHandles) {
- Label L_index_ok;
- __ cmp_and_br_short(temp2_index, (int) 0, Assembler::greaterEqual, Assembler::pn, L_index_ok);
- __ STOP("no virtual index");
- __ BIND(L_index_ok);
- }
-
- // Note: The verifier invariants allow us to ignore MemberName.clazz and vmtarget
- // at this point. And VerifyMethodHandles has already checked clazz, if needed.
-
- // get target Method* & entry point
- __ lookup_virtual_method(temp1_recv_klass, temp2_index, G5_method);
- break;
- }
-
- case vmIntrinsics::_linkToInterface:
- {
- // same as TemplateTable::invokeinterface
- // (minus the CP setup and profiling, with different argument motion)
- if (VerifyMethodHandles) {
- verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp2);
- }
-
- Register temp2_intf = temp2;
- __ load_heap_oop(member_clazz, temp2_intf, temp3);
- load_klass_from_Class(_masm, temp2_intf, temp3, temp4);
- __ verify_klass_ptr(temp2_intf);
-
- Register G5_index = G5_method;
- __ ld_ptr(member_vmindex, G5_index);
- if (VerifyMethodHandles) {
- Label L;
- __ cmp_and_br_short(G5_index, 0, Assembler::greaterEqual, Assembler::pt, L);
- __ STOP("invalid vtable index for MH.invokeInterface");
- __ bind(L);
- }
-
- // given intf, index, and recv klass, dispatch to the implementation method
- __ lookup_interface_method(temp1_recv_klass, temp2_intf,
- // note: next two args must be the same:
- G5_index, G5_method,
- temp3, temp4,
- L_incompatible_class_change_error);
- break;
- }
-
- default:
- fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid));
- break;
- }
-
- // Live at this point:
- // G5_method
- // O5_savedSP (if interpreted)
-
- // After figuring out which concrete method to call, jump into it.
- // Note that this works in the interpreter with no data motion.
- // But the compiled version will require that rcx_recv be shifted out.
- __ verify_method_ptr(G5_method);
- jump_from_method_handle(_masm, G5_method, temp1, temp2, for_compiler_entry);
-
- if (iid == vmIntrinsics::_linkToInterface) {
- __ BIND(L_incompatible_class_change_error);
- AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry());
- __ jump_to(icce, temp1);
- __ delayed()->nop();
- }
- }
-}
-
-#ifndef PRODUCT
-void trace_method_handle_stub(const char* adaptername,
- oopDesc* mh,
- intptr_t* saved_sp,
- intptr_t* args,
- intptr_t* tracing_fp) {
- bool has_mh = (strstr(adaptername, "/static") == NULL &&
- strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH
- const char* mh_reg_name = has_mh ? "G3_mh" : "G3";
- tty->print_cr("MH %s %s=" INTPTR_FORMAT " saved_sp=" INTPTR_FORMAT " args=" INTPTR_FORMAT,
- adaptername, mh_reg_name,
- p2i(mh), p2i(saved_sp), p2i(args));
-
- if (Verbose) {
- // dumping last frame with frame::describe
-
- JavaThread* p = JavaThread::active();
-
- ResourceMark rm;
- PRESERVE_EXCEPTION_MARK; // may not be needed by safer and unexpensive here
- FrameValues values;
-
- // Note: We want to allow trace_method_handle from any call site.
- // While trace_method_handle creates a frame, it may be entered
- // without a valid return PC in O7 (e.g. not just after a call).
- // Walking that frame could lead to failures due to that invalid PC.
- // => carefully detect that frame when doing the stack walking
-
- // walk up to the right frame using the "tracing_fp" argument
- intptr_t* cur_sp = StubRoutines::Sparc::flush_callers_register_windows_func()();
- frame cur_frame(cur_sp, frame::unpatchable, NULL);
-
- while (cur_frame.fp() != (intptr_t *)(STACK_BIAS+(uintptr_t)tracing_fp)) {
- cur_frame = os::get_sender_for_C_frame(&cur_frame);
- }
-
- // safely create a frame and call frame::describe
- intptr_t *dump_sp = cur_frame.sender_sp();
- intptr_t *dump_fp = cur_frame.link();
-
- bool walkable = has_mh; // whether the traced frame shoud be walkable
-
- // the sender for cur_frame is the caller of trace_method_handle
- if (walkable) {
- // The previous definition of walkable may have to be refined
- // if new call sites cause the next frame constructor to start
- // failing. Alternatively, frame constructors could be
- // modified to support the current or future non walkable
- // frames (but this is more intrusive and is not considered as
- // part of this RFE, which will instead use a simpler output).
- frame dump_frame = frame(dump_sp,
- cur_frame.sp(), // younger_sp
- false); // no adaptation
- dump_frame.describe(values, 1);
- } else {
- // Robust dump for frames which cannot be constructed from sp/younger_sp
- // Add descriptions without building a Java frame to avoid issues
- values.describe(-1, dump_fp, "fp for #1 ");
- values.describe(-1, dump_sp, "sp");
- }
-
- bool has_args = has_mh; // whether Gargs is meaningful
-
- // mark args, if seems valid (may not be valid for some adapters)
- if (has_args) {
- if ((args >= dump_sp) && (args < dump_fp)) {
- values.describe(-1, args, "*G4_args");
- }
- }
-
- // mark saved_sp, if seems valid (may not be valid for some adapters)
- intptr_t *unbiased_sp = (intptr_t *)(STACK_BIAS+(uintptr_t)saved_sp);
- const int ARG_LIMIT = 255, SLOP = 45, UNREASONABLE_STACK_MOVE = (ARG_LIMIT + SLOP);
- if ((unbiased_sp >= dump_sp - UNREASONABLE_STACK_MOVE) && (unbiased_sp < dump_fp)) {
- values.describe(-1, unbiased_sp, "*saved_sp+STACK_BIAS");
- }
-
- // Note: the unextended_sp may not be correct
- tty->print_cr(" stack layout:");
- values.print(p);
- if (has_mh && oopDesc::is_oop(mh)) {
- mh->print();
- if (java_lang_invoke_MethodHandle::is_instance(mh)) {
- if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0)
- java_lang_invoke_MethodHandle::form(mh)->print();
- }
- }
- }
-}
-
-void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) {
- if (!log_is_enabled(Info, methodhandles)) return;
- BLOCK_COMMENT("trace_method_handle {");
- // save: Gargs, O5_savedSP
- __ save_frame(16); // need space for saving required FPU state
-
- __ set((intptr_t) adaptername, O0);
- __ mov(G3_method_handle, O1);
- __ mov(I5_savedSP, O2);
- __ mov(Gargs, O3);
- __ mov(I6, O4); // frame identifier for safe stack walking
-
- // Save scratched registers that might be needed. Robustness is more
- // important than optimizing the saves for this debug only code.
-
- // save FP result, valid at some call sites (adapter_opt_return_float, ...)
- Address d_save(FP, -sizeof(jdouble) + STACK_BIAS);
- __ stf(FloatRegisterImpl::D, Ftos_d, d_save);
- // Safely save all globals but G2 (handled by call_VM_leaf) and G7
- // (OS reserved).
- __ mov(G3_method_handle, L3);
- __ mov(Gargs, L4);
- __ mov(G5_method_type, L5);
- __ mov(G6, L6);
- __ mov(G1, L1);
-
- __ call_VM_leaf(L2 /* for G2 */, CAST_FROM_FN_PTR(address, trace_method_handle_stub));
-
- __ mov(L3, G3_method_handle);
- __ mov(L4, Gargs);
- __ mov(L5, G5_method_type);
- __ mov(L6, G6);
- __ mov(L1, G1);
- __ ldf(FloatRegisterImpl::D, d_save, Ftos_d);
-
- __ restore();
- BLOCK_COMMENT("} trace_method_handle");
-}
-#endif // PRODUCT
diff --git a/src/hotspot/cpu/sparc/methodHandles_sparc.hpp b/src/hotspot/cpu/sparc/methodHandles_sparc.hpp
deleted file mode 100644
index 6638a194dec..00000000000
--- a/src/hotspot/cpu/sparc/methodHandles_sparc.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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.
- *
- */
-
-// Platform-specific definitions for method handles.
-// These definitions are inlined into class MethodHandles.
-
-// Adapters
-enum /* platform_dependent_constants */ {
- adapter_code_size = 35000 DEBUG_ONLY(+ 50000)
-};
-
-// Additional helper methods for MethodHandles code generation:
-public:
- static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp_reg, Register temp2_reg);
-
- static void verify_klass(MacroAssembler* _masm,
- Register obj_reg, SystemDictionary::WKID klass_id,
- Register temp_reg, Register temp2_reg,
- const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
-
- static void verify_method_handle(MacroAssembler* _masm, Register mh_reg,
- Register temp_reg, Register temp2_reg) {
- verify_klass(_masm, mh_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MethodHandle),
- temp_reg, temp2_reg,
- "reference is a MH");
- }
-
- static void verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) NOT_DEBUG_RETURN;
-
- // Similar to InterpreterMacroAssembler::jump_from_interpreted.
- // Takes care of special dispatch from single stepping too.
- static void jump_from_method_handle(MacroAssembler* _masm, Register method,
- Register temp, Register temp2,
- bool for_compiler_entry);
-
- static void jump_to_lambda_form(MacroAssembler* _masm,
- Register recv, Register method_temp,
- Register temp2, Register temp3,
- bool for_compiler_entry);
diff --git a/src/hotspot/cpu/sparc/nativeInst_sparc.cpp b/src/hotspot/cpu/sparc/nativeInst_sparc.cpp
deleted file mode 100644
index 94edfed8fa6..00000000000
--- a/src/hotspot/cpu/sparc/nativeInst_sparc.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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/codeCache.hpp"
-#include "code/compiledIC.hpp"
-#include "memory/resourceArea.hpp"
-#include "nativeInst_sparc.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/handles.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "utilities/ostream.hpp"
-#ifdef COMPILER1
-#include "c1/c1_Runtime1.hpp"
-#endif
-
-void NativeInstruction::set_data64_sethi(address instaddr, intptr_t x) {
- ResourceMark rm;
- CodeBuffer buf(instaddr, 10 * BytesPerInstWord );
- MacroAssembler* _masm = new MacroAssembler(&buf);
- Register destreg;
-
- destreg = inv_rd(*(unsigned int *)instaddr);
- // Generate a the new sequence
- _masm->patchable_sethi(x, destreg);
- ICache::invalidate_range(instaddr, 7 * BytesPerInstWord);
-}
-
-void NativeInstruction::verify_data64_sethi(address instaddr, intptr_t x) {
- ResourceMark rm;
- unsigned char buffer[10 * BytesPerInstWord];
- CodeBuffer buf(buffer, 10 * BytesPerInstWord);
- MacroAssembler masm(&buf);
-
- Register destreg = inv_rd(*(unsigned int *)instaddr);
- // Generate the proper sequence into a temporary buffer and compare
- // it with the original sequence.
- masm.patchable_sethi(x, destreg);
- int len = buffer - masm.pc();
- for (int i = 0; i < len; i++) {
- guarantee(instaddr[i] == buffer[i], "instructions must match");
- }
-}
-
-void NativeInstruction::verify() {
- // make sure code pattern is actually an instruction address
- address addr = addr_at(0);
- if (addr == 0 || ((intptr_t)addr & 3) != 0) {
- fatal("not an instruction address");
- }
-}
-
-void NativeInstruction::print() {
- tty->print_cr(INTPTR_FORMAT ": 0x%x", p2i(addr_at(0)), long_at(0));
-}
-
-void NativeInstruction::set_long_at(int offset, int i) {
- address addr = addr_at(offset);
- *(int*)addr = i;
- ICache::invalidate_word(addr);
-}
-
-void NativeInstruction::set_jlong_at(int offset, jlong i) {
- address addr = addr_at(offset);
- *(jlong*)addr = i;
- // Don't need to invalidate 2 words here, because
- // the flush instruction operates on doublewords.
- ICache::invalidate_word(addr);
-}
-
-void NativeInstruction::set_addr_at(int offset, address x) {
- address addr = addr_at(offset);
- assert( ((intptr_t)addr & (wordSize-1)) == 0, "set_addr_at bad address alignment");
- *(uintptr_t*)addr = (uintptr_t)x;
- // Don't need to invalidate 2 words here in the 64-bit case,
- // because the flush instruction operates on doublewords.
- ICache::invalidate_word(addr);
- // The Intel code has this assertion for NativeCall::set_destination,
- // NativeMovConstReg::set_data, NativeMovRegMem::set_offset,
- // NativeJump::set_jump_destination, and NativePushImm32::set_data
- //assert (Patching_lock->owned_by_self(), "must hold lock to patch instruction")
-}
-
-bool NativeInstruction::is_zero_test(Register ®) {
- int x = long_at(0);
- Assembler::op3s temp = (Assembler::op3s) (Assembler::sub_op3 | Assembler::cc_bit_op3);
- if (is_op3(x, temp, Assembler::arith_op) &&
- inv_immed(x) && inv_rd(x) == G0) {
- if (inv_rs1(x) == G0) {
- reg = inv_rs2(x);
- return true;
- } else if (inv_rs2(x) == G0) {
- reg = inv_rs1(x);
- return true;
- }
- }
- return false;
-}
-
-bool NativeInstruction::is_load_store_with_small_offset(Register reg) {
- int x = long_at(0);
- if (is_op(x, Assembler::ldst_op) &&
- inv_rs1(x) == reg && inv_immed(x)) {
- return true;
- }
- return false;
-}
-
-void NativeCall::verify() {
- NativeInstruction::verify();
- // make sure code pattern is actually a call instruction
- int x = long_at(0);
- if (!is_op(x, Assembler::call_op)) {
- fatal("not a call: 0x%x @ " INTPTR_FORMAT, x, p2i(instruction_address()));
- }
-}
-
-void NativeCall::print() {
- tty->print_cr(INTPTR_FORMAT ": call " INTPTR_FORMAT, p2i(instruction_address()), p2i(destination()));
-}
-
-
-// MT-safe patching of a call instruction (and following word).
-// First patches the second word, and then atomicly replaces
-// the first word with the first new instruction word.
-// Other processors might briefly see the old first word
-// followed by the new second word. This is OK if the old
-// second word is harmless, and the new second word may be
-// harmlessly executed in the delay slot of the call.
-void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) {
- assert(Patching_lock->is_locked() ||
- SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
- assert (instr_addr != NULL, "illegal address for code patching");
- NativeCall* n_call = nativeCall_at (instr_addr); // checking that it is a call
- assert(NativeCall::instruction_size == 8, "wrong instruction size; must be 8");
- int i0 = ((int*)code_buffer)[0];
- int i1 = ((int*)code_buffer)[1];
- int* contention_addr = (int*) n_call->addr_at(1*BytesPerInstWord);
- assert(inv_op(*contention_addr) == Assembler::arith_op ||
- *contention_addr == nop_instruction(),
- "must not interfere with original call");
- // The set_long_at calls do the ICacheInvalidate so we just need to do them in reverse order
- n_call->set_long_at(1*BytesPerInstWord, i1);
- n_call->set_long_at(0*BytesPerInstWord, i0);
- // NOTE: It is possible that another thread T will execute
- // only the second patched word.
- // In other words, since the original instruction is this
- // call patching_stub; nop (NativeCall)
- // and the new sequence from the buffer is this:
- // sethi %hi(K), %r; add %r, %lo(K), %r (NativeMovConstReg)
- // what T will execute is this:
- // call patching_stub; add %r, %lo(K), %r
- // thereby putting garbage into %r before calling the patching stub.
- // This is OK, because the patching stub ignores the value of %r.
-
- // Make sure the first-patched instruction, which may co-exist
- // briefly with the call, will do something harmless.
- assert(inv_op(*contention_addr) == Assembler::arith_op ||
- *contention_addr == nop_instruction(),
- "must not interfere with original call");
-}
-
-// Similar to replace_mt_safe, but just changes the destination. The
-// important thing is that free-running threads are able to execute this
-// call instruction at all times. Thus, the displacement field must be
-// instruction-word-aligned. This is always true on SPARC.
-//
-// Used in the runtime linkage of calls; see class CompiledIC.
-void NativeCall::set_destination_mt_safe(address dest) {
- assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
- CompiledICLocker::is_safe(addr_at(0)),
- "concurrent code patching");
- // set_destination uses set_long_at which does the ICache::invalidate
- set_destination(dest);
-}
-
-// Code for unit testing implementation of NativeCall class
-void NativeCall::test() {
-#ifdef ASSERT
- ResourceMark rm;
- CodeBuffer cb("test", 100, 100);
- MacroAssembler* a = new MacroAssembler(&cb);
- NativeCall *nc;
- uint idx;
- int offsets[] = {
- 0x0,
- (int)0xfffffff0,
- (int)0x7ffffff0,
- (int)0x80000000,
- 0x20,
- 0x4000,
- };
-
- VM_Version::allow_all();
-
- a->call( a->pc(), relocInfo::none );
- a->delayed()->nop();
- nc = nativeCall_at( cb.insts_begin() );
- nc->print();
-
- nc = nativeCall_overwriting_at( nc->next_instruction_address() );
- for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) {
- nc->set_destination( cb.insts_begin() + offsets[idx] );
- assert(nc->destination() == (cb.insts_begin() + offsets[idx]), "check unit test");
- nc->print();
- }
-
- nc = nativeCall_before( cb.insts_begin() + 8 );
- nc->print();
-
- VM_Version::revert();
-#endif
-}
-// End code for unit testing implementation of NativeCall class
-
-//-------------------------------------------------------------------
-
-void NativeFarCall::set_destination(address dest) {
- // Address materialized in the instruction stream, so nothing to do.
- return;
-#if 0 // What we'd do if we really did want to change the destination
- if (destination() == dest) {
- return;
- }
- ResourceMark rm;
- CodeBuffer buf(addr_at(0), instruction_size + 1);
- MacroAssembler* _masm = new MacroAssembler(&buf);
- // Generate the new sequence
- AddressLiteral(dest);
- _masm->jumpl_to(dest, O7, O7);
- ICache::invalidate_range(addr_at(0), instruction_size );
-#endif
-}
-
-void NativeFarCall::verify() {
- // make sure code pattern is actually a jumpl_to instruction
- assert((int)instruction_size == (int)NativeJump::instruction_size, "same as jump_to");
- assert((int)jmpl_offset == (int)NativeMovConstReg::add_offset, "sethi size ok");
- nativeJump_at(addr_at(0))->verify();
-}
-
-bool NativeFarCall::is_call_at(address instr) {
- return nativeInstruction_at(instr)->is_sethi();
-}
-
-void NativeFarCall::print() {
- tty->print_cr(INTPTR_FORMAT ": call " INTPTR_FORMAT, p2i(instruction_address()), p2i(destination()));
-}
-
-bool NativeFarCall::destination_is_compiled_verified_entry_point() {
- nmethod* callee = CodeCache::find_nmethod(destination());
- if (callee == NULL) {
- return false;
- } else {
- return destination() == callee->verified_entry_point();
- }
-}
-
-// MT-safe patching of a far call.
-void NativeFarCall::replace_mt_safe(address instr_addr, address code_buffer) {
- Unimplemented();
-}
-
-// Code for unit testing implementation of NativeFarCall class
-void NativeFarCall::test() {
- Unimplemented();
-}
-// End code for unit testing implementation of NativeFarCall class
-
-//-------------------------------------------------------------------
-
-
-void NativeMovConstReg::verify() {
- NativeInstruction::verify();
- // make sure code pattern is actually a "set_metadata" synthetic instruction
- // see MacroAssembler::set_oop()
- int i0 = long_at(sethi_offset);
- int i1 = long_at(add_offset);
-
- // verify the pattern "sethi %hi22(imm), reg ; add reg, %lo10(imm), reg"
- Register rd = inv_rd(i0);
- if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) {
- fatal("not a set_metadata");
- }
-}
-
-
-void NativeMovConstReg::print() {
- tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data());
-}
-
-
-intptr_t NativeMovConstReg::data() const {
- return data64(addr_at(sethi_offset), long_at(add_offset));
-}
-
-
-void NativeMovConstReg::set_data(intptr_t x) {
- set_data64_sethi(addr_at(sethi_offset), x);
- set_long_at(add_offset, set_data32_simm13( long_at(add_offset), x));
-
- // also store the value into an oop_Relocation cell, if any
- CodeBlob* cb = CodeCache::find_blob(instruction_address());
- nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL;
- if (nm != NULL) {
- RelocIterator iter(nm, instruction_address(), next_instruction_address());
- oop* oop_addr = NULL;
- Metadata** metadata_addr = NULL;
- while (iter.next()) {
- if (iter.type() == relocInfo::oop_type) {
- oop_Relocation *r = iter.oop_reloc();
- if (oop_addr == NULL) {
- oop_addr = r->oop_addr();
- *oop_addr = cast_to_oop(x);
- } else {
- assert(oop_addr == r->oop_addr(), "must be only one set-oop here");
- }
- }
- if (iter.type() == relocInfo::metadata_type) {
- metadata_Relocation *r = iter.metadata_reloc();
- if (metadata_addr == NULL) {
- metadata_addr = r->metadata_addr();
- *metadata_addr = (Metadata*)x;
- } else {
- assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here");
- }
- }
- }
- }
-}
-
-
-// Code for unit testing implementation of NativeMovConstReg class
-void NativeMovConstReg::test() {
-#ifdef ASSERT
- ResourceMark rm;
- CodeBuffer cb("test", 100, 100);
- MacroAssembler* a = new MacroAssembler(&cb);
- NativeMovConstReg* nm;
- uint idx;
- int offsets[] = {
- 0x0,
- (int)0x7fffffff,
- (int)0x80000000,
- (int)0xffffffff,
- 0x20,
- 4096,
- 4097,
- };
-
- VM_Version::allow_all();
-
- AddressLiteral al1(0xaaaabbbb, relocInfo::external_word_type);
- a->sethi(al1, I3);
- a->add(I3, al1.low10(), I3);
- AddressLiteral al2(0xccccdddd, relocInfo::external_word_type);
- a->sethi(al2, O2);
- a->add(O2, al2.low10(), O2);
-
- nm = nativeMovConstReg_at( cb.insts_begin() );
- nm->print();
-
- nm = nativeMovConstReg_at( nm->next_instruction_address() );
- for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) {
- nm->set_data( offsets[idx] );
- assert(nm->data() == offsets[idx], "check unit test");
- }
- nm->print();
-
- VM_Version::revert();
-#endif
-}
-// End code for unit testing implementation of NativeMovConstReg class
-
-//-------------------------------------------------------------------
-
-void NativeMovConstReg32::verify() {
- NativeInstruction::verify();
- // make sure code pattern is actually a "set_metadata" synthetic instruction
- // see MacroAssembler::set_oop()
- int i0 = long_at(sethi_offset);
- int i1 = long_at(add_offset);
-
- // verify the pattern "sethi %hi22(imm), reg ; add reg, %lo10(imm), reg"
- Register rd = inv_rd(i0);
- if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) {
- fatal("not a set_metadata");
- }
-}
-
-
-void NativeMovConstReg32::print() {
- tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data());
-}
-
-
-intptr_t NativeMovConstReg32::data() const {
- return data32(long_at(sethi_offset), long_at(add_offset));
-}
-
-
-void NativeMovConstReg32::set_data(intptr_t x) {
- set_long_at(sethi_offset, set_data32_sethi( long_at(sethi_offset), x));
- set_long_at(add_offset, set_data32_simm13( long_at(add_offset), x));
-
- // also store the value into an oop_Relocation cell, if any
- CodeBlob* cb = CodeCache::find_blob(instruction_address());
- nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL;
- if (nm != NULL) {
- RelocIterator iter(nm, instruction_address(), next_instruction_address());
- oop* oop_addr = NULL;
- Metadata** metadata_addr = NULL;
- while (iter.next()) {
- if (iter.type() == relocInfo::oop_type) {
- oop_Relocation *r = iter.oop_reloc();
- if (oop_addr == NULL) {
- oop_addr = r->oop_addr();
- *oop_addr = cast_to_oop(x);
- } else {
- assert(oop_addr == r->oop_addr(), "must be only one set-oop here");
- }
- }
- if (iter.type() == relocInfo::metadata_type) {
- metadata_Relocation *r = iter.metadata_reloc();
- if (metadata_addr == NULL) {
- metadata_addr = r->metadata_addr();
- *metadata_addr = (Metadata*)x;
- } else {
- assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here");
- }
- }
- }
- }
-}
-
-//-------------------------------------------------------------------
-
-void NativeMovConstRegPatching::verify() {
- NativeInstruction::verify();
- // Make sure code pattern is sethi/nop/add.
- int i0 = long_at(sethi_offset);
- int i1 = long_at(nop_offset);
- int i2 = long_at(add_offset);
- assert((int)nop_offset == (int)NativeMovConstReg::add_offset, "sethi size ok");
-
- // Verify the pattern "sethi %hi22(imm), reg; nop; add reg, %lo10(imm), reg"
- // The casual reader should note that on Sparc a nop is a special case if sethi
- // in which the destination register is %g0.
- Register rd0 = inv_rd(i0);
- Register rd1 = inv_rd(i1);
- if (!(is_op2(i0, Assembler::sethi_op2) && rd0 != G0 &&
- is_op2(i1, Assembler::sethi_op2) && rd1 == G0 && // nop is a special case of sethi
- is_op3(i2, Assembler::add_op3, Assembler::arith_op) &&
- inv_immed(i2) && (unsigned)get_simm13(i2) < (1 << 10) &&
- rd0 == inv_rs1(i2) && rd0 == inv_rd(i2))) {
- fatal("not a set_metadata");
- }
-}
-
-
-void NativeMovConstRegPatching::print() {
- tty->print_cr(INTPTR_FORMAT ": mov reg, 0x%x", p2i(instruction_address()), data());
-}
-
-
-int NativeMovConstRegPatching::data() const {
- return data64(addr_at(sethi_offset), long_at(add_offset));
-}
-
-
-void NativeMovConstRegPatching::set_data(int x) {
- set_data64_sethi(addr_at(sethi_offset), x);
- set_long_at(add_offset, set_data32_simm13(long_at(add_offset), x));
-
- // also store the value into an oop_Relocation cell, if any
- CodeBlob* cb = CodeCache::find_blob(instruction_address());
- nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL;
- if (nm != NULL) {
- RelocIterator iter(nm, instruction_address(), next_instruction_address());
- oop* oop_addr = NULL;
- Metadata** metadata_addr = NULL;
- while (iter.next()) {
- if (iter.type() == relocInfo::oop_type) {
- oop_Relocation *r = iter.oop_reloc();
- if (oop_addr == NULL) {
- oop_addr = r->oop_addr();
- *oop_addr = cast_to_oop(x);
- } else {
- assert(oop_addr == r->oop_addr(), "must be only one set-oop here");
- }
- }
- if (iter.type() == relocInfo::metadata_type) {
- metadata_Relocation *r = iter.metadata_reloc();
- if (metadata_addr == NULL) {
- metadata_addr = r->metadata_addr();
- *metadata_addr = (Metadata*)x;
- } else {
- assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here");
- }
- }
- }
- }
-}
-
-
-// Code for unit testing implementation of NativeMovConstRegPatching class
-void NativeMovConstRegPatching::test() {
-#ifdef ASSERT
- ResourceMark rm;
- CodeBuffer cb("test", 100, 100);
- MacroAssembler* a = new MacroAssembler(&cb);
- NativeMovConstRegPatching* nm;
- uint idx;
- int offsets[] = {
- 0x0,
- (int)0x7fffffff,
- (int)0x80000000,
- (int)0xffffffff,
- 0x20,
- 4096,
- 4097,
- };
-
- VM_Version::allow_all();
-
- AddressLiteral al1(0xaaaabbbb, relocInfo::external_word_type);
- a->sethi(al1, I3);
- a->nop();
- a->add(I3, al1.low10(), I3);
- AddressLiteral al2(0xccccdddd, relocInfo::external_word_type);
- a->sethi(al2, O2);
- a->nop();
- a->add(O2, al2.low10(), O2);
-
- nm = nativeMovConstRegPatching_at( cb.insts_begin() );
- nm->print();
-
- nm = nativeMovConstRegPatching_at( nm->next_instruction_address() );
- for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) {
- nm->set_data( offsets[idx] );
- assert(nm->data() == offsets[idx], "check unit test");
- }
- nm->print();
-
- VM_Version::revert();
-#endif // ASSERT
-}
-// End code for unit testing implementation of NativeMovConstRegPatching class
-
-
-//-------------------------------------------------------------------
-
-
-void NativeMovRegMem::verify() {
- NativeInstruction::verify();
- // make sure code pattern is actually a "ld" or "st" of some sort.
- int i0 = long_at(0);
- int op3 = inv_op3(i0);
-
- assert((int)add_offset == NativeMovConstReg::add_offset, "sethi size ok");
-
- if (!(is_op(i0, Assembler::ldst_op) &&
- inv_immed(i0) &&
- 0 != (op3 < op3_ldst_int_limit
- ? (1 << op3 ) & (op3_mask_ld | op3_mask_st)
- : (1 << (op3 - op3_ldst_int_limit)) & (op3_mask_ldf | op3_mask_stf))))
- {
- int i1 = long_at(ldst_offset);
- Register rd = inv_rd(i0);
-
- op3 = inv_op3(i1);
- if (!is_op(i1, Assembler::ldst_op) && rd == inv_rs2(i1) &&
- 0 != (op3 < op3_ldst_int_limit
- ? (1 << op3 ) & (op3_mask_ld | op3_mask_st)
- : (1 << (op3 - op3_ldst_int_limit)) & (op3_mask_ldf | op3_mask_stf))) {
- fatal("not a ld* or st* op");
- }
- }
-}
-
-
-void NativeMovRegMem::print() {
- if (is_immediate()) {
- // offset is a signed 13-bit immediate, so casting it to int will not lose significant bits
- tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + %d]", p2i(instruction_address()), (int)offset());
- } else {
- tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + reg]", p2i(instruction_address()));
- }
-}
-
-
-// Code for unit testing implementation of NativeMovRegMem class
-void NativeMovRegMem::test() {
-#ifdef ASSERT
- ResourceMark rm;
- CodeBuffer cb("test", 1000, 1000);
- MacroAssembler* a = new MacroAssembler(&cb);
- NativeMovRegMem* nm;
- uint idx = 0;
- uint idx1;
- int offsets[] = {
- 0x0,
- (int)0xffffffff,
- (int)0x7fffffff,
- (int)0x80000000,
- 4096,
- 4097,
- 0x20,
- 0x4000,
- };
-
- VM_Version::allow_all();
-
- AddressLiteral al1(0xffffffff, relocInfo::external_word_type);
- AddressLiteral al2(0xaaaabbbb, relocInfo::external_word_type);
- a->ldsw( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->ldsw( G5, I3, G4 ); idx++;
- a->ldsb( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->ldsb( G5, I3, G4 ); idx++;
- a->ldsh( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->ldsh( G5, I3, G4 ); idx++;
- a->lduw( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->lduw( G5, I3, G4 ); idx++;
- a->ldub( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->ldub( G5, I3, G4 ); idx++;
- a->lduh( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->lduh( G5, I3, G4 ); idx++;
- a->ldx( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->ldx( G5, I3, G4 ); idx++;
- a->ldd( G5, al1.low10(), G4 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->ldd( G5, I3, G4 ); idx++;
- a->ldf( FloatRegisterImpl::D, O2, -1, F14 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->ldf( FloatRegisterImpl::S, O0, I3, F15 ); idx++;
-
- a->stw( G5, G4, al1.low10() ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->stw( G5, G4, I3 ); idx++;
- a->stb( G5, G4, al1.low10() ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->stb( G5, G4, I3 ); idx++;
- a->sth( G5, G4, al1.low10() ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->sth( G5, G4, I3 ); idx++;
- a->stx( G5, G4, al1.low10() ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->stx( G5, G4, I3 ); idx++;
- a->std( G5, G4, al1.low10() ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->std( G5, G4, I3 ); idx++;
- a->stf( FloatRegisterImpl::S, F18, O2, -1 ); idx++;
- a->sethi(al2, I3); a->add(I3, al2.low10(), I3);
- a->stf( FloatRegisterImpl::S, F15, O0, I3 ); idx++;
-
- nm = nativeMovRegMem_at( cb.insts_begin() );
- nm->print();
- nm->set_offset( low10(0) );
- nm->print();
- nm->add_offset_in_bytes( low10(0xbb) * wordSize );
- nm->print();
-
- while (--idx) {
- nm = nativeMovRegMem_at( nm->next_instruction_address() );
- nm->print();
- for (idx1 = 0; idx1 < ARRAY_SIZE(offsets); idx1++) {
- nm->set_offset( nm->is_immediate() ? low10(offsets[idx1]) : offsets[idx1] );
- assert(nm->offset() == (nm->is_immediate() ? low10(offsets[idx1]) : offsets[idx1]),
- "check unit test");
- nm->print();
- }
- nm->add_offset_in_bytes( low10(0xbb) * wordSize );
- nm->print();
- }
-
- VM_Version::revert();
-#endif // ASSERT
-}
-
-// End code for unit testing implementation of NativeMovRegMem class
-
-
-//--------------------------------------------------------------------------------
-
-
-void NativeJump::verify() {
- NativeInstruction::verify();
- int i0 = long_at(sethi_offset);
- int i1 = long_at(jmpl_offset);
- assert((int)jmpl_offset == (int)NativeMovConstReg::add_offset, "sethi size ok");
- // verify the pattern "sethi %hi22(imm), treg ; jmpl treg, %lo10(imm), lreg"
- Register rd = inv_rd(i0);
- // In LP64, the jump instruction location varies for non relocatable
- // jumps, for example is could be sethi, xor, jmp instead of the
- // 7 instructions for sethi. So let's check sethi only.
- if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) {
- fatal("not a jump_to instruction");
- }
-}
-
-
-void NativeJump::print() {
- tty->print_cr(INTPTR_FORMAT ": jmpl reg, " INTPTR_FORMAT, p2i(instruction_address()), p2i(jump_destination()));
-}
-
-
-// Code for unit testing implementation of NativeJump class
-void NativeJump::test() {
-#ifdef ASSERT
- ResourceMark rm;
- CodeBuffer cb("test", 100, 100);
- MacroAssembler* a = new MacroAssembler(&cb);
- NativeJump* nj;
- uint idx;
- int offsets[] = {
- 0x0,
- (int)0xffffffff,
- (int)0x7fffffff,
- (int)0x80000000,
- 4096,
- 4097,
- 0x20,
- 0x4000,
- };
-
- VM_Version::allow_all();
-
- AddressLiteral al(0x7fffbbbb, relocInfo::external_word_type);
- a->sethi(al, I3);
- a->jmpl(I3, al.low10(), G0, RelocationHolder::none);
- a->delayed()->nop();
- a->sethi(al, I3);
- a->jmpl(I3, al.low10(), L3, RelocationHolder::none);
- a->delayed()->nop();
-
- nj = nativeJump_at( cb.insts_begin() );
- nj->print();
-
- nj = nativeJump_at( nj->next_instruction_address() );
- for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) {
- nj->set_jump_destination( nj->instruction_address() + offsets[idx] );
- assert(nj->jump_destination() == (nj->instruction_address() + offsets[idx]), "check unit test");
- nj->print();
- }
-
- VM_Version::revert();
-#endif // ASSERT
-}
-// End code for unit testing implementation of NativeJump class
-
-
-void NativeJump::insert(address code_pos, address entry) {
- Unimplemented();
-}
-
-// MT safe inserting of a jump over an unknown instruction sequence (used by nmethod::makeZombie)
-// The problem: jump_to is a 3-word instruction (including its delay slot).
-// Atomic write can be only with 1 word.
-void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
- // Here's one way to do it: Pre-allocate a three-word jump sequence somewhere
- // in the header of the nmethod, within a short branch's span of the patch point.
- // Set up the jump sequence using NativeJump::insert, and then use an annulled
- // unconditional branch at the target site (an atomic 1-word update).
- // Limitations: You can only patch nmethods, with any given nmethod patched at
- // most once, and the patch must be in the nmethod's header.
- // It's messy, but you can ask the CodeCache for the nmethod containing the
- // target address.
-
- // %%%%% For now, do something MT-stupid:
- ResourceMark rm;
- int code_size = 1 * BytesPerInstWord;
- CodeBuffer cb(verified_entry, code_size + 1);
- MacroAssembler* a = new MacroAssembler(&cb);
- a->ldsw(G0, 0, O7); // "ld" must agree with code in the signal handler
- ICache::invalidate_range(verified_entry, code_size);
-}
-
-
-void NativeIllegalInstruction::insert(address code_pos) {
- NativeIllegalInstruction* nii = (NativeIllegalInstruction*) nativeInstruction_at(code_pos);
- nii->set_long_at(0, illegal_instruction());
-}
-
-static int illegal_instruction_bits = 0;
-
-int NativeInstruction::illegal_instruction() {
- if (illegal_instruction_bits == 0) {
- ResourceMark rm;
- char buf[40];
- CodeBuffer cbuf((address)&buf[0], 20);
- MacroAssembler* a = new MacroAssembler(&cbuf);
- address ia = a->pc();
- a->trap(ST_RESERVED_FOR_USER_0 + 1);
- int bits = *(int*)ia;
- assert(is_op3(bits, Assembler::trap_op3, Assembler::arith_op), "bad instruction");
- illegal_instruction_bits = bits;
- assert(illegal_instruction_bits != 0, "oops");
- }
- return illegal_instruction_bits;
-}
-
-static int ic_miss_trap_bits = 0;
-
-bool NativeInstruction::is_ic_miss_trap() {
- if (ic_miss_trap_bits == 0) {
- ResourceMark rm;
- char buf[40];
- CodeBuffer cbuf((address)&buf[0], 20);
- MacroAssembler* a = new MacroAssembler(&cbuf);
- address ia = a->pc();
- a->trap(Assembler::notEqual, Assembler::ptr_cc, G0, ST_RESERVED_FOR_USER_0 + 2);
- int bits = *(int*)ia;
- assert(is_op3(bits, Assembler::trap_op3, Assembler::arith_op), "bad instruction");
- ic_miss_trap_bits = bits;
- assert(ic_miss_trap_bits != 0, "oops");
- }
- return long_at(0) == ic_miss_trap_bits;
-}
-
-
-bool NativeInstruction::is_illegal() {
- if (illegal_instruction_bits == 0) {
- return false;
- }
- return long_at(0) == illegal_instruction_bits;
-}
-
-
-void NativeGeneralJump::verify() {
- assert(((NativeInstruction *)this)->is_jump() ||
- ((NativeInstruction *)this)->is_cond_jump(), "not a general jump instruction");
-}
-
-
-void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
- Assembler::Condition condition = Assembler::always;
- int x = Assembler::op2(Assembler::br_op2) | Assembler::annul(false) |
- Assembler::cond(condition) | Assembler::wdisp((intptr_t)entry, (intptr_t)code_pos, 22);
- NativeGeneralJump* ni = (NativeGeneralJump*) nativeInstruction_at(code_pos);
- ni->set_long_at(0, x);
-}
-
-
-// MT-safe patching of a jmp instruction (and following word).
-// First patches the second word, and then atomicly replaces
-// the first word with the first new instruction word.
-// Other processors might briefly see the old first word
-// followed by the new second word. This is OK if the old
-// second word is harmless, and the new second word may be
-// harmlessly executed in the delay slot of the call.
-void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
- assert(Patching_lock->is_locked() ||
- SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
- assert (instr_addr != NULL, "illegal address for code patching");
- NativeGeneralJump* h_jump = nativeGeneralJump_at (instr_addr); // checking that it is a call
- assert(NativeGeneralJump::instruction_size == 8, "wrong instruction size; must be 8");
- int i0 = ((int*)code_buffer)[0];
- int i1 = ((int*)code_buffer)[1];
- int* contention_addr = (int*) h_jump->addr_at(1*BytesPerInstWord);
- assert(inv_op(*contention_addr) == Assembler::arith_op ||
- *contention_addr == nop_instruction(),
- "must not interfere with original call");
- // The set_long_at calls do the ICacheInvalidate so we just need to do them in reverse order
- h_jump->set_long_at(1*BytesPerInstWord, i1);
- h_jump->set_long_at(0*BytesPerInstWord, i0);
- // NOTE: It is possible that another thread T will execute
- // only the second patched word.
- // In other words, since the original instruction is this
- // jmp patching_stub; nop (NativeGeneralJump)
- // and the new sequence from the buffer is this:
- // sethi %hi(K), %r; add %r, %lo(K), %r (NativeMovConstReg)
- // what T will execute is this:
- // jmp patching_stub; add %r, %lo(K), %r
- // thereby putting garbage into %r before calling the patching stub.
- // This is OK, because the patching stub ignores the value of %r.
-
- // Make sure the first-patched instruction, which may co-exist
- // briefly with the call, will do something harmless.
- assert(inv_op(*contention_addr) == Assembler::arith_op ||
- *contention_addr == nop_instruction(),
- "must not interfere with original call");
-}
diff --git a/src/hotspot/cpu/sparc/nativeInst_sparc.hpp b/src/hotspot/cpu/sparc/nativeInst_sparc.hpp
deleted file mode 100644
index a58fdff5998..00000000000
--- a/src/hotspot/cpu/sparc/nativeInst_sparc.hpp
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_NATIVEINST_SPARC_HPP
-#define CPU_SPARC_NATIVEINST_SPARC_HPP
-
-#include "asm/macroAssembler.hpp"
-#include "runtime/icache.hpp"
-#include "runtime/os.hpp"
-
-// We have interface for the following instructions:
-// - NativeInstruction
-// - - NativeCall
-// - - NativeFarCall
-// - - NativeMovConstReg
-// - - NativeMovConstRegPatching
-// - - NativeMovRegMem
-// - - NativeJump
-// - - NativeGeneralJump
-// - - NativeIllegalInstruction
-// The base class for different kinds of native instruction abstractions.
-// Provides the primitive operations to manipulate code relative to this.
-class NativeInstruction {
- friend class Relocation;
-
- public:
- enum Sparc_specific_constants {
- nop_instruction_size = 4
- };
-
- bool is_nop() { return long_at(0) == nop_instruction(); }
- bool is_call() { return is_op(long_at(0), Assembler::call_op); }
- bool is_call_reg() { return is_op(long_at(0), Assembler::arith_op); }
- bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2)
- && inv_rd(long_at(0)) != G0); }
-
- bool sets_cc() {
- // conservative (returns true for some instructions that do not set the
- // the condition code, such as, "save".
- // Does not return true for the deprecated tagged instructions, such as, TADDcc
- int x = long_at(0);
- return (is_op(x, Assembler::arith_op) &&
- (inv_op3(x) & Assembler::cc_bit_op3) == Assembler::cc_bit_op3);
- }
- bool is_illegal();
- bool is_zombie() {
- int x = long_at(0);
- return (is_op3(x, Assembler::ldsw_op3, Assembler::ldst_op) &&
- inv_rs1(x) == G0 && inv_rd(x) == O7);
- }
- bool is_ic_miss_trap(); // Inline-cache uses a trap to detect a miss
- bool is_return() {
- // is it the output of MacroAssembler::ret or MacroAssembler::retl?
- int x = long_at(0);
- const int pc_return_offset = 8; // see frame_sparc.hpp
- return is_op3(x, Assembler::jmpl_op3, Assembler::arith_op)
- && (inv_rs1(x) == I7 || inv_rs1(x) == O7)
- && inv_immed(x) && inv_simm(x, 13) == pc_return_offset
- && inv_rd(x) == G0;
- }
- bool is_int_jump() {
- // is it the output of MacroAssembler::b?
- int x = long_at(0);
- return is_op2(x, Assembler::bp_op2) || is_op2(x, Assembler::br_op2);
- }
- bool is_float_jump() {
- // is it the output of MacroAssembler::fb?
- int x = long_at(0);
- return is_op2(x, Assembler::fbp_op2) || is_op2(x, Assembler::fb_op2);
- }
- bool is_jump() {
- return is_int_jump() || is_float_jump();
- }
- bool is_cond_jump() {
- int x = long_at(0);
- return (is_int_jump() && Assembler::inv_cond(x) != Assembler::always) ||
- (is_float_jump() && Assembler::inv_cond(x) != Assembler::f_always);
- }
-
- bool is_stack_bang() {
- int x = long_at(0);
- return is_op3(x, Assembler::stw_op3, Assembler::ldst_op) &&
- (inv_rd(x) == G0) && (inv_rs1(x) == SP) && (inv_rs2(x) == G3_scratch);
- }
-
- bool is_prefetch() {
- int x = long_at(0);
- return is_op3(x, Assembler::prefetch_op3, Assembler::ldst_op);
- }
-
- bool is_membar() {
- int x = long_at(0);
- return is_op3(x, Assembler::membar_op3, Assembler::arith_op) &&
- (inv_rd(x) == G0) && (inv_rs1(x) == O7);
- }
-
- bool is_safepoint_poll() {
- int x = long_at(0);
- return is_op3(x, Assembler::ldx_op3, Assembler::ldst_op) &&
- (inv_rd(x) == G0) && (inv_immed(x) ? Assembler::inv_simm13(x) == 0 : inv_rs2(x) == G0);
- }
-
- bool is_zero_test(Register ®);
- bool is_load_store_with_small_offset(Register reg);
-
- public:
- static int nop_instruction() { return Assembler::op(Assembler::branch_op) | Assembler::op2(Assembler::sethi_op2); }
- static int illegal_instruction(); // the output of __ breakpoint_trap()
- static int call_instruction(address destination, address pc) { return Assembler::op(Assembler::call_op) | Assembler::wdisp((intptr_t)destination, (intptr_t)pc, 30); }
-
-protected:
- address addr_at(int offset) const { return address(this) + offset; }
- int long_at(int offset) const { return *(int*)addr_at(offset); }
- void set_long_at(int offset, int i); /* deals with I-cache */
- void set_jlong_at(int offset, jlong i); /* deals with I-cache */
- void set_addr_at(int offset, address x); /* deals with I-cache */
-
- address instruction_address() const { return addr_at(0); }
- address next_instruction_address() const { return addr_at(BytesPerInstWord); }
-
- static bool is_op( int x, Assembler::ops opval) {
- return Assembler::inv_op(x) == opval;
- }
- static bool is_op2(int x, Assembler::op2s op2val) {
- return Assembler::inv_op(x) == Assembler::branch_op && Assembler::inv_op2(x) == op2val;
- }
- static bool is_op3(int x, Assembler::op3s op3val, Assembler::ops opval) {
- return Assembler::inv_op(x) == opval && Assembler::inv_op3(x) == op3val;
- }
-
- // utilities to help subclasses decode:
- static Register inv_rd( int x ) { return Assembler::inv_rd( x); }
- static Register inv_rs1( int x ) { return Assembler::inv_rs1(x); }
- static Register inv_rs2( int x ) { return Assembler::inv_rs2(x); }
-
- static bool inv_immed( int x ) { return Assembler::inv_immed(x); }
- static bool inv_annul( int x ) { return (Assembler::annul(true) & x) != 0; }
- static int inv_cond( int x ) { return Assembler::inv_cond(x); }
-
- static int inv_op( int x ) { return Assembler::inv_op( x); }
- static int inv_op2( int x ) { return Assembler::inv_op2(x); }
- static int inv_op3( int x ) { return Assembler::inv_op3(x); }
-
- static int inv_simm( int x, int nbits ) { return Assembler::inv_simm(x, nbits); }
- static intptr_t inv_wdisp( int x, int nbits ) { return Assembler::inv_wdisp( x, 0, nbits); }
- static intptr_t inv_wdisp16( int x ) { return Assembler::inv_wdisp16(x, 0); }
- static int branch_destination_offset(int x) { return MacroAssembler::branch_destination(x, 0); }
- static int patch_branch_destination_offset(int dest_offset, int x) {
- return MacroAssembler::patched_branch(dest_offset, x, 0);
- }
-
- // utility for checking if x is either of 2 small constants
- static bool is_either(int x, int k1, int k2) {
- // return x == k1 || x == k2;
- return (1 << x) & (1 << k1 | 1 << k2);
- }
-
- // utility for checking overflow of signed instruction fields
- static bool fits_in_simm(int x, int nbits) {
- // cf. Assembler::assert_signed_range()
- // return -(1 << nbits-1) <= x && x < ( 1 << nbits-1),
- return (unsigned)(x + (1 << nbits-1)) < (unsigned)(1 << nbits);
- }
-
- // set a signed immediate field
- static int set_simm(int insn, int imm, int nbits) {
- return (insn &~ Assembler::simm(-1, nbits)) | Assembler::simm(imm, nbits);
- }
-
- // set a wdisp field (disp should be the difference of two addresses)
- static int set_wdisp(int insn, intptr_t disp, int nbits) {
- return (insn &~ Assembler::wdisp((intptr_t)-4, (intptr_t)0, nbits)) | Assembler::wdisp(disp, 0, nbits);
- }
-
- static int set_wdisp16(int insn, intptr_t disp) {
- return (insn &~ Assembler::wdisp16((intptr_t)-4, 0)) | Assembler::wdisp16(disp, 0);
- }
-
- // get a simm13 field from an arithmetic or memory instruction
- static int get_simm13(int insn) {
- assert(is_either(Assembler::inv_op(insn),
- Assembler::arith_op, Assembler::ldst_op) &&
- (insn & Assembler::immed(true)), "must have a simm13 field");
- return Assembler::inv_simm(insn, 13);
- }
-
- // set the simm13 field of an arithmetic or memory instruction
- static bool set_simm13(int insn, int imm) {
- get_simm13(insn); // tickle the assertion check
- return set_simm(insn, imm, 13);
- }
-
- // combine the fields of a sethi stream (7 instructions ) and an add, jmp or ld/st
- static intptr_t data64( address pc, int arith_insn ) {
- assert(is_op2(*(unsigned int *)pc, Assembler::sethi_op2), "must be sethi");
- intptr_t hi = (intptr_t)gethi( (unsigned int *)pc );
- intptr_t lo = (intptr_t)get_simm13(arith_insn);
- assert((unsigned)lo < (1 << 10), "offset field of set_metadata must be 10 bits");
- return hi | lo;
- }
-
- // Regenerate the instruction sequence that performs the 64 bit
- // sethi. This only does the sethi. The disp field (bottom 10 bits)
- // must be handled separately.
- static void set_data64_sethi(address instaddr, intptr_t x);
- static void verify_data64_sethi(address instaddr, intptr_t x);
-
- // combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st)
- static int data32(int sethi_insn, int arith_insn) {
- assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi");
- int hi = Assembler::inv_hi22(sethi_insn);
- int lo = get_simm13(arith_insn);
- assert((unsigned)lo < (1 << 10), "offset field of set_metadata must be 10 bits");
- return hi | lo;
- }
-
- static int set_data32_sethi(int sethi_insn, int imm) {
- // note that Assembler::hi22 clips the low 10 bits for us
- assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi");
- return (sethi_insn &~ Assembler::hi22(-1)) | Assembler::hi22(imm);
- }
-
- static int set_data32_simm13(int arith_insn, int imm) {
- get_simm13(arith_insn); // tickle the assertion check
- int imm10 = Assembler::low10(imm);
- return (arith_insn &~ Assembler::simm(-1, 13)) | Assembler::simm(imm10, 13);
- }
-
- static int low10(int imm) {
- return Assembler::low10(imm);
- }
-
- // Perform the inverse of the LP64 Macroassembler::sethi
- // routine. Extracts the 54 bits of address from the instruction
- // stream. This routine must agree with the sethi routine in
- // assembler_inline_sparc.hpp
- static address gethi( unsigned int *pc ) {
- int i = 0;
- uintptr_t adr;
- // We first start out with the real sethi instruction
- assert(is_op2(*pc, Assembler::sethi_op2), "in gethi - must be sethi");
- adr = (unsigned int)Assembler::inv_hi22( *(pc++) );
- i++;
- while ( i < 7 ) {
- // We're done if we hit a nop
- if ( (int)*pc == nop_instruction() ) break;
- assert ( Assembler::inv_op(*pc) == Assembler::arith_op, "in gethi - must be arith_op" );
- switch ( Assembler::inv_op3(*pc) ) {
- case Assembler::xor_op3:
- adr ^= (intptr_t)get_simm13( *pc );
- return ( (address)adr );
- break;
- case Assembler::sll_op3:
- adr <<= ( *pc & 0x3f );
- break;
- case Assembler::or_op3:
- adr |= (intptr_t)get_simm13( *pc );
- break;
- default:
- assert ( 0, "in gethi - Should not reach here" );
- break;
- }
- pc++;
- i++;
- }
- return ( (address)adr );
- }
-
- public:
- void verify();
- void print();
-
- // unit test stuff
- static void test() {} // override for testing
-
- inline friend NativeInstruction* nativeInstruction_at(address address);
-};
-
-inline NativeInstruction* nativeInstruction_at(address address) {
- NativeInstruction* inst = (NativeInstruction*)address;
-#ifdef ASSERT
- inst->verify();
-#endif
- return inst;
-}
-
-
-
-//-----------------------------------------------------------------------------
-
-// The NativeCall is an abstraction for accessing/manipulating native call imm32 instructions.
-// (used to manipulate inline caches, primitive & dll calls, etc.)
-class NativeCall;
-
-inline NativeCall* nativeCall_at(address instr);
-inline NativeCall* nativeCall_overwriting_at(address instr,
- address destination = NULL);
-inline NativeCall* nativeCall_before(address return_address);
-class NativeCall: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- instruction_size = 8,
- return_address_offset = 8,
- call_displacement_width = 30,
- displacement_offset = 0,
- instruction_offset = 0
- };
- address instruction_address() const { return addr_at(0); }
- address next_instruction_address() const { return addr_at(instruction_size); }
- address return_address() const { return addr_at(return_address_offset); }
-
- address destination() const { return inv_wdisp(long_at(0), call_displacement_width) + instruction_address(); }
- address displacement_address() const { return addr_at(displacement_offset); }
- void set_destination(address dest) { set_long_at(0, set_wdisp(long_at(0), dest - instruction_address(), call_displacement_width)); }
- void set_destination_mt_safe(address dest);
-
- void verify_alignment() {} // do nothing on sparc
- void verify();
- void print();
-
- // unit test stuff
- static void test();
-
- // Creation
- friend inline NativeCall* nativeCall_at(address instr);
- friend NativeCall* nativeCall_overwriting_at(address instr, address destination) {
- // insert a "blank" call:
- NativeCall* call = (NativeCall*)instr;
- call->set_long_at(0 * BytesPerInstWord, call_instruction(destination, instr));
- call->set_long_at(1 * BytesPerInstWord, nop_instruction());
- assert(call->addr_at(2 * BytesPerInstWord) - instr == instruction_size, "instruction size");
- // check its structure now:
- assert(nativeCall_at(instr)->destination() == destination, "correct call destination");
- return call;
- }
-
- friend inline NativeCall* nativeCall_before(address return_address) {
- NativeCall* call = (NativeCall*)(return_address - return_address_offset);
- #ifdef ASSERT
- call->verify();
- #endif
- return call;
- }
-
- static bool is_call_at(address instr) {
- return nativeInstruction_at(instr)->is_call();
- }
-
- static bool is_call_before(address instr) {
- return nativeInstruction_at(instr - return_address_offset)->is_call();
- }
-
- static bool is_call_to(address instr, address target) {
- return nativeInstruction_at(instr)->is_call() &&
- nativeCall_at(instr)->destination() == target;
- }
-
- // MT-safe patching of a call instruction.
- static void insert(address code_pos, address entry) {
- (void)nativeCall_overwriting_at(code_pos, entry);
- }
-
- static void replace_mt_safe(address instr_addr, address code_buffer);
-};
-inline NativeCall* nativeCall_at(address instr) {
- NativeCall* call = (NativeCall*)instr;
-#ifdef ASSERT
- call->verify();
-#endif
- return call;
-}
-
-class NativeCallReg: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- instruction_size = 8,
- return_address_offset = 8,
- instruction_offset = 0
- };
-
- address next_instruction_address() const {
- return addr_at(instruction_size);
- }
-};
-
-// The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere
-// instructions in the sparcv9 vm. Used to call native methods which may be loaded
-// anywhere in the address space, possibly out of reach of a call instruction.
-
-// The format of this extended-range call is:
-// jumpl_to addr, lreg
-// == sethi %hi54(addr), O7 ; jumpl O7, %lo10(addr), O7 ;
-// That is, it is essentially the same as a NativeJump.
-class NativeFarCall;
-inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination = NULL);
-inline NativeFarCall* nativeFarCall_at(address instr);
-class NativeFarCall: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- // instruction_size includes the delay slot instruction.
- instruction_size = 9 * BytesPerInstWord,
- return_address_offset = 9 * BytesPerInstWord,
- jmpl_offset = 7 * BytesPerInstWord,
- displacement_offset = 0,
- instruction_offset = 0
- };
- address instruction_address() const { return addr_at(0); }
- address next_instruction_address() const { return addr_at(instruction_size); }
- address return_address() const { return addr_at(return_address_offset); }
-
- address destination() const {
- return (address) data64(addr_at(0), long_at(jmpl_offset));
- }
- address displacement_address() const { return addr_at(displacement_offset); }
- void set_destination(address dest);
-
- bool destination_is_compiled_verified_entry_point();
-
- void verify();
- void print();
-
- // unit test stuff
- static void test();
-
- // Creation
- friend inline NativeFarCall* nativeFarCall_at(address instr) {
- NativeFarCall* call = (NativeFarCall*)instr;
- #ifdef ASSERT
- call->verify();
- #endif
- return call;
- }
-
- friend inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination) {
- Unimplemented();
- NativeFarCall* call = (NativeFarCall*)instr;
- return call;
- }
-
- friend NativeFarCall* nativeFarCall_before(address return_address) {
- NativeFarCall* call = (NativeFarCall*)(return_address - return_address_offset);
- #ifdef ASSERT
- call->verify();
- #endif
- return call;
- }
-
- static bool is_call_at(address instr);
-
- // MT-safe patching of a call instruction.
- static void insert(address code_pos, address entry) {
- (void)nativeFarCall_overwriting_at(code_pos, entry);
- }
- static void replace_mt_safe(address instr_addr, address code_buffer);
-};
-
-
-// An interface for accessing/manipulating 32 bit native set_metadata imm, reg instructions
-// (used to manipulate inlined data references, etc.)
-// set_metadata imm, reg
-// == sethi %hi22(imm), reg ; add reg, %lo10(imm), reg
-class NativeMovConstReg32;
-inline NativeMovConstReg32* nativeMovConstReg32_at(address address);
-class NativeMovConstReg32: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- sethi_offset = 0,
- add_offset = 4,
- instruction_size = 8
- };
-
- address instruction_address() const { return addr_at(0); }
- address next_instruction_address() const { return addr_at(instruction_size); }
-
- // (The [set_]data accessor respects oop_type relocs also.)
- intptr_t data() const;
- void set_data(intptr_t x);
-
- // report the destination register
- Register destination() { return inv_rd(long_at(sethi_offset)); }
-
- void verify();
- void print();
-
- // unit test stuff
- static void test();
-
- // Creation
- friend inline NativeMovConstReg32* nativeMovConstReg32_at(address address) {
- NativeMovConstReg32* test = (NativeMovConstReg32*)address;
- #ifdef ASSERT
- test->verify();
- #endif
- return test;
- }
-};
-
-// An interface for accessing/manipulating native set_metadata imm, reg instructions.
-// (used to manipulate inlined data references, etc.)
-// set_metadata imm, reg
-// == sethi %hi22(imm), reg ; add reg, %lo10(imm), reg
-class NativeMovConstReg;
-inline NativeMovConstReg* nativeMovConstReg_at(address address);
-class NativeMovConstReg: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- sethi_offset = 0,
- add_offset = 7 * BytesPerInstWord,
- instruction_size = 8 * BytesPerInstWord
- };
-
- address instruction_address() const { return addr_at(0); }
- address next_instruction_address() const { return addr_at(instruction_size); }
-
- // (The [set_]data accessor respects oop_type relocs also.)
- intptr_t data() const;
- void set_data(intptr_t x);
-
- // report the destination register
- Register destination() { return inv_rd(long_at(sethi_offset)); }
-
- void verify();
- void print();
-
- // unit test stuff
- static void test();
-
- // Creation
- friend inline NativeMovConstReg* nativeMovConstReg_at(address address) {
- NativeMovConstReg* test = (NativeMovConstReg*)address;
- #ifdef ASSERT
- test->verify();
- #endif
- return test;
- }
-
-
- friend NativeMovConstReg* nativeMovConstReg_before(address address) {
- NativeMovConstReg* test = (NativeMovConstReg*)(address - instruction_size);
- #ifdef ASSERT
- test->verify();
- #endif
- return test;
- }
-
-};
-
-
-// An interface for accessing/manipulating native set_metadata imm, reg instructions.
-// (used to manipulate inlined data references, etc.)
-// set_metadata imm, reg
-// == sethi %hi22(imm), reg; nop; add reg, %lo10(imm), reg
-//
-// Note that it is identical to NativeMovConstReg with the exception of a nop between the
-// sethi and the add. The nop is required to be in the delay slot of the call instruction
-// which overwrites the sethi during patching.
-class NativeMovConstRegPatching;
-inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address);
-class NativeMovConstRegPatching: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- sethi_offset = 0,
- nop_offset = 7 * BytesPerInstWord,
- add_offset = nop_offset + BytesPerInstWord,
- instruction_size = add_offset + BytesPerInstWord
- };
-
- address instruction_address() const { return addr_at(0); }
- address next_instruction_address() const { return addr_at(instruction_size); }
-
- // (The [set_]data accessor respects oop_type relocs also.)
- int data() const;
- void set_data(int x);
-
- // report the destination register
- Register destination() { return inv_rd(long_at(sethi_offset)); }
-
- void verify();
- void print();
-
- // unit test stuff
- static void test();
-
- // Creation
- friend inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
- NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)address;
- #ifdef ASSERT
- test->verify();
- #endif
- return test;
- }
-
-
- friend NativeMovConstRegPatching* nativeMovConstRegPatching_before(address address) {
- NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_size);
- #ifdef ASSERT
- test->verify();
- #endif
- return test;
- }
-
-};
-
-
-// An interface for accessing/manipulating native memory ops
-// ld* [reg + offset], reg
-// st* reg, [reg + offset]
-// sethi %hi(imm), reg; add reg, %lo(imm), reg; ld* [reg1 + reg], reg2
-// sethi %hi(imm), reg; add reg, %lo(imm), reg; st* reg2, [reg1 + reg]
-// Ops covered: {lds,ldu,st}{w,b,h}, {ld,st}{d,x}
-//
-class NativeMovRegMem;
-inline NativeMovRegMem* nativeMovRegMem_at (address address);
-class NativeMovRegMem: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- op3_mask_ld = 1 << Assembler::lduw_op3 |
- 1 << Assembler::ldub_op3 |
- 1 << Assembler::lduh_op3 |
- 1 << Assembler::ldd_op3 |
- 1 << Assembler::ldsw_op3 |
- 1 << Assembler::ldsb_op3 |
- 1 << Assembler::ldsh_op3 |
- 1 << Assembler::ldx_op3,
- op3_mask_st = 1 << Assembler::stw_op3 |
- 1 << Assembler::stb_op3 |
- 1 << Assembler::sth_op3 |
- 1 << Assembler::std_op3 |
- 1 << Assembler::stx_op3,
- op3_ldst_int_limit = Assembler::ldf_op3,
- op3_mask_ldf = 1 << (Assembler::ldf_op3 - op3_ldst_int_limit) |
- 1 << (Assembler::lddf_op3 - op3_ldst_int_limit),
- op3_mask_stf = 1 << (Assembler::stf_op3 - op3_ldst_int_limit) |
- 1 << (Assembler::stdf_op3 - op3_ldst_int_limit),
-
- offset_width = 13,
- sethi_offset = 0,
- add_offset = 7 * BytesPerInstWord,
- ldst_offset = add_offset + BytesPerInstWord
- };
- bool is_immediate() const {
- // check if instruction is ld* [reg + offset], reg or st* reg, [reg + offset]
- int i0 = long_at(0);
- return (is_op(i0, Assembler::ldst_op));
- }
-
- address instruction_address() const { return addr_at(0); }
-
- int num_bytes_to_end_of_patch() const {
- return is_immediate()? BytesPerInstWord :
- NativeMovConstReg::instruction_size;
- }
-
- intptr_t offset() const {
- return is_immediate()? inv_simm(long_at(0), offset_width) :
- nativeMovConstReg_at(addr_at(0))->data();
- }
- void set_offset(intptr_t x) {
- if (is_immediate()) {
- guarantee(fits_in_simm(x, offset_width), "data block offset overflow");
- set_long_at(0, set_simm(long_at(0), x, offset_width));
- } else
- nativeMovConstReg_at(addr_at(0))->set_data(x);
- }
-
- void add_offset_in_bytes(intptr_t radd_offset) {
- set_offset (offset() + radd_offset);
- }
-
- void verify();
- void print ();
-
- // unit test stuff
- static void test();
-
- private:
- friend inline NativeMovRegMem* nativeMovRegMem_at (address address) {
- NativeMovRegMem* test = (NativeMovRegMem*)address;
- #ifdef ASSERT
- test->verify();
- #endif
- return test;
- }
-};
-
-
-// An interface for accessing/manipulating native jumps
-// jump_to addr
-// == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), G0 ;
-// jumpl_to addr, lreg
-// == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), lreg ;
-class NativeJump;
-inline NativeJump* nativeJump_at(address address);
-class NativeJump: public NativeInstruction {
- private:
- void guarantee_displacement(int disp, int width) {
- guarantee(fits_in_simm(disp, width + 2), "branch displacement overflow");
- }
-
- public:
- enum Sparc_specific_constants {
- sethi_offset = 0,
- jmpl_offset = 7 * BytesPerInstWord,
- instruction_size = 9 * BytesPerInstWord // includes delay slot
- };
-
- address instruction_address() const { return addr_at(0); }
- address next_instruction_address() const { return addr_at(instruction_size); }
-
- address jump_destination() const {
- return (address) data64(instruction_address(), long_at(jmpl_offset));
- }
- void set_jump_destination(address dest) {
- set_data64_sethi( instruction_address(), (intptr_t)dest);
- set_long_at(jmpl_offset, set_data32_simm13( long_at(jmpl_offset), (intptr_t)dest));
- }
-
- // Creation
- friend inline NativeJump* nativeJump_at(address address) {
- NativeJump* jump = (NativeJump*)address;
- #ifdef ASSERT
- jump->verify();
- #endif
- return jump;
- }
-
- void verify();
- void print();
-
- // Unit testing stuff
- static void test();
-
- // Insertion of native jump instruction
- static void insert(address code_pos, address entry);
- // MT-safe insertion of native jump at verified method entry
- static void check_verified_entry_alignment(address entry, address verified_entry) {
- // nothing to do for sparc.
- }
- static void patch_verified_entry(address entry, address verified_entry, address dest);
-};
-
-
-
-// Despite the name, handles only simple branches.
-class NativeGeneralJump;
-inline NativeGeneralJump* nativeGeneralJump_at(address address);
-class NativeGeneralJump: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- instruction_size = 8
- };
-
- address instruction_address() const { return addr_at(0); }
- address jump_destination() const { return addr_at(0) + branch_destination_offset(long_at(0)); }
- void set_jump_destination(address dest) {
- int patched_instr = patch_branch_destination_offset(dest - addr_at(0), long_at(0));
- set_long_at(0, patched_instr);
- }
- NativeInstruction *delay_slot_instr() { return nativeInstruction_at(addr_at(4));}
- void fill_delay_slot(int instr) { set_long_at(4, instr);}
- Assembler::Condition condition() {
- int x = long_at(0);
- return (Assembler::Condition) Assembler::inv_cond(x);
- }
-
- // Creation
- friend inline NativeGeneralJump* nativeGeneralJump_at(address address) {
- NativeGeneralJump* jump = (NativeGeneralJump*)(address);
-#ifdef ASSERT
- jump->verify();
-#endif
- return jump;
- }
-
- // Insertion of native general jump instruction
- static void insert_unconditional(address code_pos, address entry);
- static void replace_mt_safe(address instr_addr, address code_buffer);
-
- void verify();
-};
-
-
-class NativeIllegalInstruction: public NativeInstruction {
- public:
- enum Sparc_specific_constants {
- instruction_size = 4
- };
-
- // Insert illegal opcode as specific address
- static void insert(address code_pos);
-};
-
-#endif // CPU_SPARC_NATIVEINST_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/registerMap_sparc.hpp b/src/hotspot/cpu/sparc/registerMap_sparc.hpp
deleted file mode 100644
index 182c824ed73..00000000000
--- a/src/hotspot/cpu/sparc/registerMap_sparc.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_REGISTERMAP_SPARC_HPP
-#define CPU_SPARC_REGISTERMAP_SPARC_HPP
-
-// machine-dependent implemention for register maps
- friend class frame;
- friend class MethodHandles;
-
- private:
- intptr_t* _window; // register window save area (for L and I regs)
- intptr_t* _younger_window; // previous save area (for O regs, if needed)
-
- address pd_location(VMReg reg) const;
- void pd_clear();
- void pd_initialize_from(const RegisterMap* map) {
- _window = map->_window;
- _younger_window = map->_younger_window;
- _location_valid[0] = 0; // avoid the shift_individual_registers game
- }
- void pd_initialize() {
- _window = NULL;
- _younger_window = NULL;
- _location_valid[0] = 0; // avoid the shift_individual_registers game
- }
- void shift_window(intptr_t* sp, intptr_t* younger_sp) {
- _window = sp;
- _younger_window = younger_sp;
- // Throw away locations for %i, %o, and %l registers:
- // But do not throw away %g register locs.
- if (_location_valid[0] != 0) shift_individual_registers();
- }
- void shift_individual_registers();
- // When popping out of compiled frames, we make all IRegs disappear.
- void make_integer_regs_unsaved() { _location_valid[0] = 0; }
-
-#endif // CPU_SPARC_REGISTERMAP_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/register_definitions_sparc.cpp b/src/hotspot/cpu/sparc/register_definitions_sparc.cpp
deleted file mode 100644
index 4a956f1e7b3..00000000000
--- a/src/hotspot/cpu/sparc/register_definitions_sparc.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2002, 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.
- *
- */
-
-// Note: precompiled headers can not be used in this file because of the above
-// definition
-
-#include "asm/assembler.hpp"
-#include "asm/register.hpp"
-#include "interp_masm_sparc.hpp"
-#include "register_sparc.hpp"
-
-REGISTER_DEFINITION(Register, noreg);
-
-REGISTER_DEFINITION(Register, G0);
-REGISTER_DEFINITION(Register, G1);
-REGISTER_DEFINITION(Register, G2);
-REGISTER_DEFINITION(Register, G3);
-REGISTER_DEFINITION(Register, G4);
-REGISTER_DEFINITION(Register, G5);
-REGISTER_DEFINITION(Register, G6);
-REGISTER_DEFINITION(Register, G7);
-
-REGISTER_DEFINITION(Register, O0);
-REGISTER_DEFINITION(Register, O1);
-REGISTER_DEFINITION(Register, O2);
-REGISTER_DEFINITION(Register, O3);
-REGISTER_DEFINITION(Register, O4);
-REGISTER_DEFINITION(Register, O5);
-REGISTER_DEFINITION(Register, O6);
-REGISTER_DEFINITION(Register, O7);
-
-REGISTER_DEFINITION(Register, L0);
-REGISTER_DEFINITION(Register, L1);
-REGISTER_DEFINITION(Register, L2);
-REGISTER_DEFINITION(Register, L3);
-REGISTER_DEFINITION(Register, L4);
-REGISTER_DEFINITION(Register, L5);
-REGISTER_DEFINITION(Register, L6);
-REGISTER_DEFINITION(Register, L7);
-
-REGISTER_DEFINITION(Register, I0);
-REGISTER_DEFINITION(Register, I1);
-REGISTER_DEFINITION(Register, I2);
-REGISTER_DEFINITION(Register, I3);
-REGISTER_DEFINITION(Register, I4);
-REGISTER_DEFINITION(Register, I5);
-REGISTER_DEFINITION(Register, I6);
-REGISTER_DEFINITION(Register, I7);
-
-REGISTER_DEFINITION(Register, FP);
-REGISTER_DEFINITION(Register, SP);
-
-REGISTER_DEFINITION(FloatRegister, fnoreg);
-REGISTER_DEFINITION(FloatRegister, F0);
-REGISTER_DEFINITION(FloatRegister, F1);
-REGISTER_DEFINITION(FloatRegister, F2);
-REGISTER_DEFINITION(FloatRegister, F3);
-REGISTER_DEFINITION(FloatRegister, F4);
-REGISTER_DEFINITION(FloatRegister, F5);
-REGISTER_DEFINITION(FloatRegister, F6);
-REGISTER_DEFINITION(FloatRegister, F7);
-REGISTER_DEFINITION(FloatRegister, F8);
-REGISTER_DEFINITION(FloatRegister, F9);
-REGISTER_DEFINITION(FloatRegister, F10);
-REGISTER_DEFINITION(FloatRegister, F11);
-REGISTER_DEFINITION(FloatRegister, F12);
-REGISTER_DEFINITION(FloatRegister, F13);
-REGISTER_DEFINITION(FloatRegister, F14);
-REGISTER_DEFINITION(FloatRegister, F15);
-REGISTER_DEFINITION(FloatRegister, F16);
-REGISTER_DEFINITION(FloatRegister, F17);
-REGISTER_DEFINITION(FloatRegister, F18);
-REGISTER_DEFINITION(FloatRegister, F19);
-REGISTER_DEFINITION(FloatRegister, F20);
-REGISTER_DEFINITION(FloatRegister, F21);
-REGISTER_DEFINITION(FloatRegister, F22);
-REGISTER_DEFINITION(FloatRegister, F23);
-REGISTER_DEFINITION(FloatRegister, F24);
-REGISTER_DEFINITION(FloatRegister, F25);
-REGISTER_DEFINITION(FloatRegister, F26);
-REGISTER_DEFINITION(FloatRegister, F27);
-REGISTER_DEFINITION(FloatRegister, F28);
-REGISTER_DEFINITION(FloatRegister, F29);
-REGISTER_DEFINITION(FloatRegister, F30);
-REGISTER_DEFINITION(FloatRegister, F31);
-REGISTER_DEFINITION(FloatRegister, F32);
-REGISTER_DEFINITION(FloatRegister, F34);
-REGISTER_DEFINITION(FloatRegister, F36);
-REGISTER_DEFINITION(FloatRegister, F38);
-REGISTER_DEFINITION(FloatRegister, F40);
-REGISTER_DEFINITION(FloatRegister, F42);
-REGISTER_DEFINITION(FloatRegister, F44);
-REGISTER_DEFINITION(FloatRegister, F46);
-REGISTER_DEFINITION(FloatRegister, F48);
-REGISTER_DEFINITION(FloatRegister, F50);
-REGISTER_DEFINITION(FloatRegister, F52);
-REGISTER_DEFINITION(FloatRegister, F54);
-REGISTER_DEFINITION(FloatRegister, F56);
-REGISTER_DEFINITION(FloatRegister, F58);
-REGISTER_DEFINITION(FloatRegister, F60);
-REGISTER_DEFINITION(FloatRegister, F62);
-
-
-REGISTER_DEFINITION( Register, Otos_i);
-REGISTER_DEFINITION( Register, Otos_l);
-REGISTER_DEFINITION( Register, Otos_l1);
-REGISTER_DEFINITION( Register, Otos_l2);
-REGISTER_DEFINITION(FloatRegister, Ftos_f);
-REGISTER_DEFINITION(FloatRegister, Ftos_d);
-REGISTER_DEFINITION(FloatRegister, Ftos_d1);
-REGISTER_DEFINITION(FloatRegister, Ftos_d2);
-
-
-REGISTER_DEFINITION(Register, G2_thread);
-REGISTER_DEFINITION(Register, G6_heapbase);
-REGISTER_DEFINITION(Register, G5_method);
-REGISTER_DEFINITION(Register, G5_megamorphic_method);
-REGISTER_DEFINITION(Register, G5_inline_cache_reg);
-REGISTER_DEFINITION(Register, Gargs);
-REGISTER_DEFINITION(Register, L7_thread_cache);
-REGISTER_DEFINITION(Register, Gframe_size);
-REGISTER_DEFINITION(Register, G1_scratch);
-REGISTER_DEFINITION(Register, G3_scratch);
-REGISTER_DEFINITION(Register, G4_scratch);
-REGISTER_DEFINITION(Register, Gtemp);
-REGISTER_DEFINITION(Register, Lentry_args);
-
-// JSR 292
-REGISTER_DEFINITION(Register, G5_method_type);
-REGISTER_DEFINITION(Register, G3_method_handle);
-REGISTER_DEFINITION(Register, L7_mh_SP_save);
-
-REGISTER_DEFINITION(Register, Lesp);
-REGISTER_DEFINITION(Register, Lbcp);
-REGISTER_DEFINITION(Register, Lmonitors);
-REGISTER_DEFINITION(Register, Lbyte_code);
-REGISTER_DEFINITION(Register, Llast_SP);
-REGISTER_DEFINITION(Register, Lscratch);
-REGISTER_DEFINITION(Register, Lscratch2);
-REGISTER_DEFINITION(Register, LcpoolCache);
-REGISTER_DEFINITION(Register, I5_savedSP);
-REGISTER_DEFINITION(Register, O5_savedSP);
-REGISTER_DEFINITION(Register, IdispatchAddress);
-REGISTER_DEFINITION(Register, ImethodDataPtr);
-REGISTER_DEFINITION(Register, Lmethod);
-REGISTER_DEFINITION(Register, Llocals);
-REGISTER_DEFINITION(Register, Oexception);
-REGISTER_DEFINITION(Register, Oissuing_pc);
diff --git a/src/hotspot/cpu/sparc/register_sparc.cpp b/src/hotspot/cpu/sparc/register_sparc.cpp
deleted file mode 100644
index 4ed28c6a0b5..00000000000
--- a/src/hotspot/cpu/sparc/register_sparc.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "register_sparc.hpp"
-
-const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers << 1;
-const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::max_gpr + FloatRegisterImpl::number_of_registers;
-
-const char* RegisterImpl::name() const {
- const char* names[number_of_registers] = {
- "G0", "G1", "G2", "G3", "G4", "G5", "G6", "G7",
- "O0", "O1", "O2", "O3", "O4", "O5", "SP", "O7",
- "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7",
- "I0", "I1", "I2", "I3", "I4", "I5", "FP", "I7"
- };
- return is_valid() ? names[encoding()] : "noreg";
-}
-
-
-const char* FloatRegisterImpl::name() const {
- const char* names[number_of_registers] = {
- "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9",
- "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19",
- "F20", "F21", "F22", "F23", "F24", "F25", "F26", "F27", "F28", "F29",
- "F30", "F31", "F32", "F33?", "F34", "F35?", "F36", "F37?", "F38", "F39?",
- "F40", "F41?", "F42", "F43?", "F44", "F45?", "F46", "F47?", "F48", "F49?",
- "F50", "F51?", "F52", "F53?", "F54", "F55?", "F56", "F57?", "F58", "F59?",
- "F60", "F61?", "F62"
- };
- return is_valid() ? names[encoding()] : "fnoreg";
-}
diff --git a/src/hotspot/cpu/sparc/register_sparc.hpp b/src/hotspot/cpu/sparc/register_sparc.hpp
deleted file mode 100644
index d68c19fc0db..00000000000
--- a/src/hotspot/cpu/sparc/register_sparc.hpp
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_REGISTER_SPARC_HPP
-#define CPU_SPARC_REGISTER_SPARC_HPP
-
-#include "asm/register.hpp"
-
-// forward declaration
-class Address;
-class VMRegImpl;
-typedef VMRegImpl* VMReg;
-
-
-// Use Register as shortcut
-class RegisterImpl;
-typedef RegisterImpl* Register;
-
-
-inline Register as_Register(int encoding) {
- return (Register)(intptr_t) encoding;
-}
-
-// The implementation of integer registers for the SPARC architecture
-class RegisterImpl: public AbstractRegisterImpl {
- public:
- enum {
- log_set_size = 3, // the number of bits to encode the set register number
- number_of_sets = 4, // the number of registers sets (in, local, out, global)
- number_of_registers = number_of_sets << log_set_size,
-
- iset_no = 3, ibase = iset_no << log_set_size, // the in register set
- lset_no = 2, lbase = lset_no << log_set_size, // the local register set
- oset_no = 1, obase = oset_no << log_set_size, // the output register set
- gset_no = 0, gbase = gset_no << log_set_size // the global register set
- };
-
-
- friend Register as_Register(int encoding);
- // set specific construction
- friend Register as_iRegister(int number);
- friend Register as_lRegister(int number);
- friend Register as_oRegister(int number);
- friend Register as_gRegister(int number);
-
- inline VMReg as_VMReg();
-
- // accessors
- int encoding() const { assert(is_valid(), "invalid register"); return value(); }
- const char* name() const;
-
- // testers
- bool is_valid() const { return (0 <= (value()&0x7F) && (value()&0x7F) < number_of_registers); }
- bool is_even() const { return (encoding() & 1) == 0; }
- bool is_in() const { return (encoding() >> log_set_size) == iset_no; }
- bool is_local() const { return (encoding() >> log_set_size) == lset_no; }
- bool is_out() const { return (encoding() >> log_set_size) == oset_no; }
- bool is_global() const { return (encoding() >> log_set_size) == gset_no; }
-
- // derived registers, offsets, and addresses
- Register successor() const { return as_Register(encoding() + 1); }
-
- int input_number() const {
- assert(is_in(), "must be input register");
- return encoding() - ibase;
- }
-
- Register after_save() const {
- assert(is_out() || is_global(), "register not visible after save");
- return is_out() ? as_Register(encoding() + (ibase - obase)) : (const Register)this;
- }
-
- Register after_restore() const {
- assert(is_in() || is_global(), "register not visible after restore");
- return is_in() ? as_Register(encoding() + (obase - ibase)) : (const Register)this;
- }
-
- int sp_offset_in_saved_window() const {
- assert(is_in() || is_local(), "only i and l registers are saved in frame");
- return encoding() - lbase;
- }
-
- inline Address address_in_saved_window() const; // implemented in assembler_sparc.hpp
-};
-
-
-// set specific construction
-inline Register as_iRegister(int number) { return as_Register(RegisterImpl::ibase + number); }
-inline Register as_lRegister(int number) { return as_Register(RegisterImpl::lbase + number); }
-inline Register as_oRegister(int number) { return as_Register(RegisterImpl::obase + number); }
-inline Register as_gRegister(int number) { return as_Register(RegisterImpl::gbase + number); }
-
-// The integer registers of the SPARC architecture
-
-CONSTANT_REGISTER_DECLARATION(Register, noreg , (-1));
-
-CONSTANT_REGISTER_DECLARATION(Register, G0 , (RegisterImpl::gbase + 0));
-CONSTANT_REGISTER_DECLARATION(Register, G1 , (RegisterImpl::gbase + 1));
-CONSTANT_REGISTER_DECLARATION(Register, G2 , (RegisterImpl::gbase + 2));
-CONSTANT_REGISTER_DECLARATION(Register, G3 , (RegisterImpl::gbase + 3));
-CONSTANT_REGISTER_DECLARATION(Register, G4 , (RegisterImpl::gbase + 4));
-CONSTANT_REGISTER_DECLARATION(Register, G5 , (RegisterImpl::gbase + 5));
-CONSTANT_REGISTER_DECLARATION(Register, G6 , (RegisterImpl::gbase + 6));
-CONSTANT_REGISTER_DECLARATION(Register, G7 , (RegisterImpl::gbase + 7));
-
-CONSTANT_REGISTER_DECLARATION(Register, O0 , (RegisterImpl::obase + 0));
-CONSTANT_REGISTER_DECLARATION(Register, O1 , (RegisterImpl::obase + 1));
-CONSTANT_REGISTER_DECLARATION(Register, O2 , (RegisterImpl::obase + 2));
-CONSTANT_REGISTER_DECLARATION(Register, O3 , (RegisterImpl::obase + 3));
-CONSTANT_REGISTER_DECLARATION(Register, O4 , (RegisterImpl::obase + 4));
-CONSTANT_REGISTER_DECLARATION(Register, O5 , (RegisterImpl::obase + 5));
-CONSTANT_REGISTER_DECLARATION(Register, O6 , (RegisterImpl::obase + 6));
-CONSTANT_REGISTER_DECLARATION(Register, O7 , (RegisterImpl::obase + 7));
-
-CONSTANT_REGISTER_DECLARATION(Register, L0 , (RegisterImpl::lbase + 0));
-CONSTANT_REGISTER_DECLARATION(Register, L1 , (RegisterImpl::lbase + 1));
-CONSTANT_REGISTER_DECLARATION(Register, L2 , (RegisterImpl::lbase + 2));
-CONSTANT_REGISTER_DECLARATION(Register, L3 , (RegisterImpl::lbase + 3));
-CONSTANT_REGISTER_DECLARATION(Register, L4 , (RegisterImpl::lbase + 4));
-CONSTANT_REGISTER_DECLARATION(Register, L5 , (RegisterImpl::lbase + 5));
-CONSTANT_REGISTER_DECLARATION(Register, L6 , (RegisterImpl::lbase + 6));
-CONSTANT_REGISTER_DECLARATION(Register, L7 , (RegisterImpl::lbase + 7));
-
-CONSTANT_REGISTER_DECLARATION(Register, I0 , (RegisterImpl::ibase + 0));
-CONSTANT_REGISTER_DECLARATION(Register, I1 , (RegisterImpl::ibase + 1));
-CONSTANT_REGISTER_DECLARATION(Register, I2 , (RegisterImpl::ibase + 2));
-CONSTANT_REGISTER_DECLARATION(Register, I3 , (RegisterImpl::ibase + 3));
-CONSTANT_REGISTER_DECLARATION(Register, I4 , (RegisterImpl::ibase + 4));
-CONSTANT_REGISTER_DECLARATION(Register, I5 , (RegisterImpl::ibase + 5));
-CONSTANT_REGISTER_DECLARATION(Register, I6 , (RegisterImpl::ibase + 6));
-CONSTANT_REGISTER_DECLARATION(Register, I7 , (RegisterImpl::ibase + 7));
-
-CONSTANT_REGISTER_DECLARATION(Register, FP , (RegisterImpl::ibase + 6));
-CONSTANT_REGISTER_DECLARATION(Register, SP , (RegisterImpl::obase + 6));
-
-// Use FloatRegister as shortcut
-class FloatRegisterImpl;
-typedef FloatRegisterImpl* FloatRegister;
-
-
-// construction
-inline FloatRegister as_FloatRegister(int encoding) {
- return (FloatRegister)(intptr_t)encoding;
-}
-
-// The implementation of float registers for the SPARC architecture
-
-class FloatRegisterImpl: public AbstractRegisterImpl {
- public:
- enum {
- number_of_registers = 64
- };
-
- enum Width {
- S = 1, D = 2, Q = 3
- };
-
- // construction
- inline VMReg as_VMReg( );
-
- // accessors
- int encoding() const { assert(is_valid(), "invalid register"); return value(); }
-
- public:
- int encoding(Width w) const {
- const int c = encoding();
- switch (w) {
- case S:
- assert(c < 32, "bad single float register");
- return c;
-
- case D:
- assert(c < 64 && (c & 1) == 0, "bad double float register");
- return (c & 0x1e) | ((c & 0x20) >> 5);
-
- case Q:
- assert(c < 64 && (c & 3) == 0, "bad quad float register");
- return (c & 0x1c) | ((c & 0x20) >> 5);
- }
- ShouldNotReachHere();
- return -1;
- }
-
- bool is_valid() const { return 0 <= value() && value() < number_of_registers; }
- bool is_even() const { return (encoding() & 1) == 0; }
-
- const char* name() const;
-
- FloatRegister successor() const { return as_FloatRegister(encoding() + 1); }
-};
-
-
-// The float registers of the SPARC architecture
-
-CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg , (-1));
-
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F0 , ( 0));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F1 , ( 1));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F2 , ( 2));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F3 , ( 3));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F4 , ( 4));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F5 , ( 5));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F6 , ( 6));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F7 , ( 7));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F8 , ( 8));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F9 , ( 9));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F10 , (10));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F11 , (11));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F12 , (12));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F13 , (13));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F14 , (14));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F15 , (15));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F16 , (16));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F17 , (17));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F18 , (18));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F19 , (19));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F20 , (20));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F21 , (21));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F22 , (22));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F23 , (23));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F24 , (24));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F25 , (25));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F26 , (26));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F27 , (27));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F28 , (28));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F29 , (29));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F30 , (30));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F31 , (31));
-
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F32 , (32));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F34 , (34));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F36 , (36));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F38 , (38));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F40 , (40));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F42 , (42));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F44 , (44));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F46 , (46));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F48 , (48));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F50 , (50));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F52 , (52));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F54 , (54));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F56 , (56));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F58 , (58));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F60 , (60));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, F62 , (62));
-
-// Maximum number of incoming arguments that can be passed in i registers.
-const int SPARC_ARGS_IN_REGS_NUM = 6;
-
-class ConcreteRegisterImpl : public AbstractRegisterImpl {
- public:
- enum {
- // This number must be large enough to cover REG_COUNT (defined by c2) registers.
- // There is no requirement that any ordering here matches any ordering c2 gives
- // it's optoregs.
- number_of_registers = 2*RegisterImpl::number_of_registers +
- FloatRegisterImpl::number_of_registers +
- 1 + // ccr
- 4 // fcc
- };
- static const int max_gpr;
- static const int max_fpr;
-
-};
-
-// Single, Double and Quad fp reg classes. These exist to map the ADLC
-// encoding for a floating point register, to the FloatRegister number
-// desired by the macroassembler. A FloatRegister is a number between
-// 0 and 63 passed around as a pointer. For ADLC, an fp register encoding
-// is the actual bit encoding used by the sparc hardware. When ADLC used
-// the macroassembler to generate an instruction that references, e.g., a
-// double fp reg, it passed the bit encoding to the macroassembler via
-// as_FloatRegister, which, for double regs > 30, returns an illegal
-// register number.
-//
-// Therefore we provide the following classes for use by ADLC. Their
-// sole purpose is to convert from sparc register encodings to FloatRegisters.
-// At some future time, we might replace FloatRegister with these classes,
-// hence the definitions of as_xxxFloatRegister as class methods rather
-// than as external inline routines.
-
-class SingleFloatRegisterImpl;
-typedef SingleFloatRegisterImpl *SingleFloatRegister;
-
-inline FloatRegister as_SingleFloatRegister(int encoding);
-class SingleFloatRegisterImpl {
- public:
- friend inline FloatRegister as_SingleFloatRegister(int encoding) {
- assert(encoding < 32, "bad single float register encoding");
- return as_FloatRegister(encoding);
- }
-};
-
-
-class DoubleFloatRegisterImpl;
-typedef DoubleFloatRegisterImpl *DoubleFloatRegister;
-
-inline FloatRegister as_DoubleFloatRegister(int encoding);
-class DoubleFloatRegisterImpl {
- public:
- friend inline FloatRegister as_DoubleFloatRegister(int encoding) {
- assert(encoding < 32, "bad double float register encoding");
- return as_FloatRegister( ((encoding & 1) << 5) | (encoding & 0x1e) );
- }
-};
-
-
-class QuadFloatRegisterImpl;
-typedef QuadFloatRegisterImpl *QuadFloatRegister;
-
-class QuadFloatRegisterImpl {
- public:
- friend FloatRegister as_QuadFloatRegister(int encoding) {
- assert(encoding < 32 && ((encoding & 2) == 0), "bad quad float register encoding");
- return as_FloatRegister( ((encoding & 1) << 5) | (encoding & 0x1c) );
- }
-};
-
-#endif // CPU_SPARC_REGISTER_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/relocInfo_sparc.cpp b/src/hotspot/cpu/sparc/relocInfo_sparc.cpp
deleted file mode 100644
index bb1287d7d61..00000000000
--- a/src/hotspot/cpu/sparc/relocInfo_sparc.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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/relocInfo.hpp"
-#include "nativeInst_sparc.hpp"
-#include "oops/compressedOops.inline.hpp"
-#include "oops/klass.inline.hpp"
-#include "oops/oop.hpp"
-#include "runtime/safepoint.hpp"
-
-void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) {
- NativeInstruction* ip = nativeInstruction_at(addr());
- jint inst = ip->long_at(0);
- assert(inst != NativeInstruction::illegal_instruction(), "no breakpoint");
- switch (Assembler::inv_op(inst)) {
-
- case Assembler::ldst_op:
- #ifdef ASSERT
- switch (Assembler::inv_op3(inst)) {
- case Assembler::lduw_op3:
- case Assembler::ldub_op3:
- case Assembler::lduh_op3:
- case Assembler::ldd_op3:
- case Assembler::ldsw_op3:
- case Assembler::ldsb_op3:
- case Assembler::ldsh_op3:
- case Assembler::ldx_op3:
- case Assembler::ldf_op3:
- case Assembler::lddf_op3:
- case Assembler::stw_op3:
- case Assembler::stb_op3:
- case Assembler::sth_op3:
- case Assembler::std_op3:
- case Assembler::stx_op3:
- case Assembler::stf_op3:
- case Assembler::stdf_op3:
- case Assembler::casa_op3:
- case Assembler::casxa_op3:
- break;
- default:
- ShouldNotReachHere();
- }
- goto do_non_sethi;
- #endif
-
- case Assembler::arith_op:
- #ifdef ASSERT
- switch (Assembler::inv_op3(inst)) {
- case Assembler::or_op3:
- case Assembler::add_op3:
- case Assembler::jmpl_op3:
- break;
- default:
- ShouldNotReachHere();
- }
- do_non_sethi:;
- #endif
- {
- guarantee(Assembler::inv_immed(inst), "must have a simm13 field");
- int simm13 = Assembler::low10((intptr_t)x) + o;
- guarantee(Assembler::is_simm13(simm13), "offset can't overflow simm13");
- inst &= ~Assembler::simm( -1, 13);
- inst |= Assembler::simm(simm13, 13);
- if (verify_only) {
- guarantee(ip->long_at(0) == inst, "instructions must match");
- } else {
- ip->set_long_at(0, inst);
- }
- }
- break;
-
- case Assembler::branch_op:
- {
- jint inst2;
- guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi");
- if (format() != 0) {
- assert(type() == relocInfo::oop_type || type() == relocInfo::metadata_type, "only narrow oops or klasses case");
- jint np = type() == relocInfo::oop_type ? CompressedOops::encode((oop)x) : CompressedKlassPointers::encode((Klass*)x);
- inst &= ~Assembler::hi22(-1);
- inst |= Assembler::hi22((intptr_t)np);
- if (verify_only) {
- guarantee(ip->long_at(0) == inst, "instructions must match");
- } else {
- ip->set_long_at(0, inst);
- }
- inst2 = ip->long_at( NativeInstruction::nop_instruction_size );
- guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op");
- if (verify_only) {
- guarantee(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np),
- "instructions must match");
- } else {
- ip->set_long_at(NativeInstruction::nop_instruction_size, NativeInstruction::set_data32_simm13( inst2, (intptr_t)np));
- }
- break;
- }
- if (verify_only) {
- ip->verify_data64_sethi( ip->addr_at(0), (intptr_t)x );
- } else {
- ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x );
- }
- }
- break;
-
- default:
- guarantee(false, "instruction must perform arithmetic or memory access");
- }
-}
-
-
-address Relocation::pd_call_destination(address orig_addr) {
- intptr_t adj = 0;
- if (orig_addr != NULL) {
- // We just moved this call instruction from orig_addr to addr().
- // This means its target will appear to have grown by addr() - orig_addr.
- adj = -( addr() - orig_addr );
- }
- if (NativeCall::is_call_at(addr())) {
- NativeCall* call = nativeCall_at(addr());
- return call->destination() + adj;
- }
- if (NativeFarCall::is_call_at(addr())) {
- NativeFarCall* call = nativeFarCall_at(addr());
- return call->destination() + adj;
- }
- // Special case: Patchable branch local to the code cache.
- // This will break badly if the code cache grows larger than a few Mb.
- NativeGeneralJump* br = nativeGeneralJump_at(addr());
- return br->jump_destination() + adj;
-}
-
-
-void Relocation::pd_set_call_destination(address x) {
- if (NativeCall::is_call_at(addr())) {
- NativeCall* call = nativeCall_at(addr());
- call->set_destination(x);
- return;
- }
- if (NativeFarCall::is_call_at(addr())) {
- NativeFarCall* call = nativeFarCall_at(addr());
- call->set_destination(x);
- return;
- }
- // Special case: Patchable branch local to the code cache.
- // This will break badly if the code cache grows larger than a few Mb.
- NativeGeneralJump* br = nativeGeneralJump_at(addr());
- br->set_jump_destination(x);
-}
-
-
-address* Relocation::pd_address_in_code() {
- // SPARC never embeds addresses in code, at present.
- //assert(type() == relocInfo::oop_type, "only oops are inlined at present");
- return (address*)addr();
-}
-
-
-address Relocation::pd_get_address_from_code() {
- // SPARC never embeds addresses in code, at present.
- //assert(type() == relocInfo::oop_type, "only oops are inlined at present");
- return *(address*)addr();
-}
-
-void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
-}
-
-void metadata_Relocation::pd_fix_value(address x) {
-}
diff --git a/src/hotspot/cpu/sparc/relocInfo_sparc.hpp b/src/hotspot/cpu/sparc/relocInfo_sparc.hpp
deleted file mode 100644
index 0dc2b7fcda5..00000000000
--- a/src/hotspot/cpu/sparc/relocInfo_sparc.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_RELOCINFO_SPARC_HPP
-#define CPU_SPARC_RELOCINFO_SPARC_HPP
-
- // machine-dependent parts of class relocInfo
- private:
- enum {
- // Since SPARC instructions are whole words,
- // the two low-order offset bits can always be discarded.
- offset_unit = 4,
-
- // There is no need for format bits; the instructions are
- // sufficiently self-identifying.
- // Except narrow oops in 64-bits VM.
- format_width = 1
- };
-
- public:
-
- // This platform has no oops in the code that are not also
- // listed in the oop section.
- static bool mustIterateImmediateOopsInCode() { return false; }
-
-//Reconciliation History
-// 1.3 97/10/15 15:38:36 relocInfo_i486.hpp
-// 1.4 97/12/08 16:01:06 relocInfo_i486.hpp
-// 1.5 98/01/23 01:34:55 relocInfo_i486.hpp
-// 1.6 98/02/27 15:44:53 relocInfo_i486.hpp
-// 1.6 98/03/12 14:47:13 relocInfo_i486.hpp
-// 1.8 99/06/22 16:37:50 relocInfo_i486.hpp
-// 1.9 99/07/16 11:12:11 relocInfo_i486.hpp
-//End
-
-#endif // CPU_SPARC_RELOCINFO_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/runtime_sparc.cpp b/src/hotspot/cpu/sparc/runtime_sparc.cpp
deleted file mode 100644
index 5336bf43bee..00000000000
--- a/src/hotspot/cpu/sparc/runtime_sparc.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 1998, 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"
-#ifdef COMPILER2
-#include "asm/macroAssembler.inline.hpp"
-#include "classfile/systemDictionary.hpp"
-#include "code/vmreg.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/resourceArea.hpp"
-#include "nativeInst_sparc.hpp"
-#include "opto/runtime.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/globalDefinitions.hpp"
-#include "vmreg_sparc.inline.hpp"
-#endif
-
-
-#define __ masm->
-
-//------------------------------ generate_exception_blob ---------------------------
-// creates exception blob at the end
-// Using exception blob, this code is jumped from a compiled method.
-// (see emit_exception_handler in sparc.ad file)
-//
-// Given an exception pc at a call we call into the runtime for the
-// handler in this method. This handler might merely restore state
-// (i.e. callee save registers) unwind the frame and jump to the
-// exception handler for the nmethod if there is no Java level handler
-// for the nmethod.
-//
-// This code is entered with a jmp.
-//
-// Arguments:
-// O0: exception oop
-// O1: exception pc
-//
-// Results:
-// O0: exception oop
-// O1: exception pc in caller or ???
-// destination: exception handler of caller
-//
-// Note: the exception pc MUST be at a call (precise debug information)
-//
-void OptoRuntime::generate_exception_blob() {
- // allocate space for code
- ResourceMark rm;
- int pad = VerifyThread ? 256 : 0;// Extra slop space for more verify code
-
- // setup code generation tools
- // Measured 8/7/03 at 256 in 32bit debug build (no VerifyThread)
- // Measured 8/7/03 at 528 in 32bit debug build (VerifyThread)
- CodeBuffer buffer("exception_blob", 600+pad, 512);
- MacroAssembler* masm = new MacroAssembler(&buffer);
-
- int framesize_in_bytes = __ total_frame_size_in_bytes(0);
- int framesize_in_words = framesize_in_bytes / wordSize;
- int framesize_in_slots = framesize_in_bytes / sizeof(jint);
-
- Label L;
-
- int start = __ offset();
-
- __ verify_thread();
- __ st_ptr(Oexception, G2_thread, JavaThread::exception_oop_offset());
- __ st_ptr(Oissuing_pc, G2_thread, JavaThread::exception_pc_offset());
-
- // This call does all the hard work. It checks if an exception catch
- // exists in the method.
- // If so, it returns the handler address.
- // If the nmethod has been deoptimized and it had a handler the handler
- // address is the deopt blob unpack_with_exception entry.
- //
- // If no handler exists it prepares for stack-unwinding, restoring the callee-save
- // registers of the frame being removed.
- //
- __ save_frame(0);
-
- __ mov(G2_thread, O0);
- __ set_last_Java_frame(SP, noreg);
- __ save_thread(L7_thread_cache);
-
- // This call can block at exit and nmethod can be deoptimized at that
- // point. If the nmethod had a catch point we would jump to the
- // now deoptimized catch point and fall thru the vanilla deopt
- // path and lose the exception
- // Sure would be simpler if this call didn't block!
- __ call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C), relocInfo::runtime_call_type);
- __ delayed()->mov(L7_thread_cache, O0);
-
- // Set an oopmap for the call site. This oopmap will only be used if we
- // are unwinding the stack. Hence, all locations will be dead.
- // Callee-saved registers will be the same as the frame above (i.e.,
- // handle_exception_stub), since they were restored when we got the
- // exception.
-
- OopMapSet *oop_maps = new OopMapSet();
- oop_maps->add_gc_map( __ offset()-start, new OopMap(framesize_in_slots, 0));
-
- __ bind(L);
- __ restore_thread(L7_thread_cache);
- __ reset_last_Java_frame();
-
- __ mov(O0, G3_scratch); // Move handler address to temp
- __ restore();
-
- // Restore SP from L7 if the exception PC is a MethodHandle call site.
- __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), O7);
- __ tst(O7);
- __ movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP);
-
- // G3_scratch contains handler address
- // Since this may be the deopt blob we must set O7 to look like we returned
- // from the original pc that threw the exception
-
- __ ld_ptr(G2_thread, JavaThread::exception_pc_offset(), O7);
- __ sub(O7, frame::pc_return_offset, O7);
-
-
- assert(Assembler::is_simm13(in_bytes(JavaThread::exception_oop_offset())), "exception offset overflows simm13, following ld instruction cannot be in delay slot");
- __ ld_ptr(G2_thread, JavaThread::exception_oop_offset(), Oexception); // O0
-#ifdef ASSERT
- __ st_ptr(G0, G2_thread, JavaThread::exception_handler_pc_offset());
- __ st_ptr(G0, G2_thread, JavaThread::exception_pc_offset());
-#endif
- __ JMP(G3_scratch, 0);
- // Clear the exception oop so GC no longer processes it as a root.
- __ delayed()->st_ptr(G0, G2_thread, JavaThread::exception_oop_offset());
-
- // -------------
- // make sure all code is generated
- masm->flush();
-
- _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize_in_words);
-}
diff --git a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp
deleted file mode 100644
index 0e2c15ff1c6..00000000000
--- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp
+++ /dev/null
@@ -1,3248 +0,0 @@
-/*
- * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "asm/macroAssembler.inline.hpp"
-#include "code/debugInfoRec.hpp"
-#include "code/icBuffer.hpp"
-#include "code/vtableStubs.hpp"
-#include "gc/shared/gcLocker.hpp"
-#include "interpreter/interpreter.hpp"
-#include "logging/log.hpp"
-#include "memory/resourceArea.hpp"
-#include "oops/compiledICHolder.hpp"
-#include "oops/klass.inline.hpp"
-#include "runtime/safepointMechanism.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/align.hpp"
-#include "vmreg_sparc.inline.hpp"
-#ifdef COMPILER1
-#include "c1/c1_Runtime1.hpp"
-#endif
-#ifdef COMPILER2
-#include "opto/runtime.hpp"
-#endif
-#if INCLUDE_JVMCI
-#include "jvmci/jvmciJavaClasses.hpp"
-#endif
-
-#define __ masm->
-
-
-class RegisterSaver {
-
- // Used for saving volatile registers. This is Gregs, Fregs, I/L/O.
- // The Oregs are problematic. In the 32bit build the compiler can
- // have O registers live with 64 bit quantities. A window save will
- // cut the heads off of the registers. We have to do a very extensive
- // stack dance to save and restore these properly.
-
- // Note that the Oregs problem only exists if we block at either a polling
- // page exception a compiled code safepoint that was not originally a call
- // or deoptimize following one of these kinds of safepoints.
-
- // Lots of registers to save. For all builds, a window save will preserve
- // the %i and %l registers. For the 32-bit longs-in-two entries and 64-bit
- // builds a window-save will preserve the %o registers. In the LION build
- // we need to save the 64-bit %o registers which requires we save them
- // before the window-save (as then they become %i registers and get their
- // heads chopped off on interrupt). We have to save some %g registers here
- // as well.
- enum {
- // This frame's save area. Includes extra space for the native call:
- // vararg's layout space and the like. Briefly holds the caller's
- // register save area.
- call_args_area = frame::register_save_words_sp_offset +
- frame::memory_parameter_word_sp_offset*wordSize,
- // Make sure save locations are always 8 byte aligned.
- // can't use align_up because it doesn't produce compile time constant
- start_of_extra_save_area = ((call_args_area + 7) & ~7),
- g1_offset = start_of_extra_save_area, // g-regs needing saving
- g3_offset = g1_offset+8,
- g4_offset = g3_offset+8,
- g5_offset = g4_offset+8,
- o0_offset = g5_offset+8,
- o1_offset = o0_offset+8,
- o2_offset = o1_offset+8,
- o3_offset = o2_offset+8,
- o4_offset = o3_offset+8,
- o5_offset = o4_offset+8,
- start_of_flags_save_area = o5_offset+8,
- ccr_offset = start_of_flags_save_area,
- fsr_offset = ccr_offset + 8,
- d00_offset = fsr_offset+8, // Start of float save area
- register_save_size = d00_offset+8*32
- };
-
-
- public:
-
- static int Oexception_offset() { return o0_offset; };
- static int G3_offset() { return g3_offset; };
- static int G5_offset() { return g5_offset; };
- static OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words);
- static void restore_live_registers(MacroAssembler* masm);
-
- // During deoptimization only the result register need to be restored
- // all the other values have already been extracted.
-
- static void restore_result_registers(MacroAssembler* masm);
-};
-
-OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words) {
- // Record volatile registers as callee-save values in an OopMap so their save locations will be
- // propagated to the caller frame's RegisterMap during StackFrameStream construction (needed for
- // deoptimization; see compiledVFrame::create_stack_value). The caller's I, L and O registers
- // are saved in register windows - I's and L's in the caller's frame and O's in the stub frame
- // (as the stub's I's) when the runtime routine called by the stub creates its frame.
- int i;
- // Always make the frame size 16 byte aligned.
- int frame_size = align_up(additional_frame_words + register_save_size, 16);
- // OopMap frame size is in c2 stack slots (sizeof(jint)) not bytes or words
- int frame_size_in_slots = frame_size / sizeof(jint);
- // CodeBlob frame size is in words.
- *total_frame_words = frame_size / wordSize;
- // OopMap* map = new OopMap(*total_frame_words, 0);
- OopMap* map = new OopMap(frame_size_in_slots, 0);
-
- __ save(SP, -frame_size, SP);
-
-
- int debug_offset = 0;
- // Save the G's
- __ stx(G1, SP, g1_offset+STACK_BIAS);
- map->set_callee_saved(VMRegImpl::stack2reg((g1_offset + debug_offset)>>2), G1->as_VMReg());
-
- __ stx(G3, SP, g3_offset+STACK_BIAS);
- map->set_callee_saved(VMRegImpl::stack2reg((g3_offset + debug_offset)>>2), G3->as_VMReg());
-
- __ stx(G4, SP, g4_offset+STACK_BIAS);
- map->set_callee_saved(VMRegImpl::stack2reg((g4_offset + debug_offset)>>2), G4->as_VMReg());
-
- __ stx(G5, SP, g5_offset+STACK_BIAS);
- map->set_callee_saved(VMRegImpl::stack2reg((g5_offset + debug_offset)>>2), G5->as_VMReg());
-
- // This is really a waste but we'll keep things as they were for now
- if (true) {
- }
-
-
- // Save the flags
- __ rdccr( G5 );
- __ stx(G5, SP, ccr_offset+STACK_BIAS);
- __ stxfsr(SP, fsr_offset+STACK_BIAS);
-
- // Save all the FP registers: 32 doubles (32 floats correspond to the 2 halves of the first 16 doubles)
- int offset = d00_offset;
- for( int i=0; iset_callee_saved(VMRegImpl::stack2reg(offset>>2), f->as_VMReg());
- map->set_callee_saved(VMRegImpl::stack2reg((offset + sizeof(float))>>2), f->as_VMReg()->next());
- offset += sizeof(double);
- }
-
- // And we're done.
-
- return map;
-}
-
-
-// Pop the current frame and restore all the registers that we
-// saved.
-void RegisterSaver::restore_live_registers(MacroAssembler* masm) {
-
- // Restore all the FP registers
- for( int i=0; i 8;
-}
-
-size_t SharedRuntime::trampoline_size() {
- return 40;
-}
-
-void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
- __ set((intptr_t)destination, G3_scratch);
- __ JMP(G3_scratch, 0);
- __ delayed()->nop();
-}
-
-// The java_calling_convention describes stack locations as ideal slots on
-// a frame with no abi restrictions. Since we must observe abi restrictions
-// (like the placement of the register window) the slots must be biased by
-// the following value.
-static int reg2offset(VMReg r) {
- return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
-}
-
-static VMRegPair reg64_to_VMRegPair(Register r) {
- VMRegPair ret;
- if (wordSize == 8) {
- ret.set2(r->as_VMReg());
- } else {
- ret.set_pair(r->successor()->as_VMReg(), r->as_VMReg());
- }
- return ret;
-}
-
-// ---------------------------------------------------------------------------
-// Read the array of BasicTypes from a signature, and compute where the
-// arguments should go. Values in the VMRegPair regs array refer to 4-byte (VMRegImpl::stack_slot_size)
-// quantities. Values less than VMRegImpl::stack0 are registers, those above
-// refer to 4-byte stack slots. All stack slots are based off of the window
-// top. VMRegImpl::stack0 refers to the first slot past the 16-word window,
-// and VMRegImpl::stack0+1 refers to the memory word 4-byes higher. Register
-// values 0-63 (up to RegisterImpl::number_of_registers) are the 64-bit
-// integer registers. Values 64-95 are the (32-bit only) float registers.
-// Each 32-bit quantity is given its own number, so the integer registers
-// (in either 32- or 64-bit builds) use 2 numbers. For example, there is
-// an O0-low and an O0-high. Essentially, all int register numbers are doubled.
-
-// Register results are passed in O0-O5, for outgoing call arguments. To
-// convert to incoming arguments, convert all O's to I's. The regs array
-// refer to the low and hi 32-bit words of 64-bit registers or stack slots.
-// If the regs[].second() field is set to VMRegImpl::Bad(), it means it's unused (a
-// 32-bit value was passed). If both are VMRegImpl::Bad(), it means no value was
-// passed (used as a placeholder for the other half of longs and doubles in
-// the 64-bit build). regs[].second() is either VMRegImpl::Bad() or regs[].second() is
-// regs[].first()+1 (regs[].first() may be misaligned in the C calling convention).
-// Sparc never passes a value in regs[].second() but not regs[].first() (regs[].first()
-// == VMRegImpl::Bad() && regs[].second() != VMRegImpl::Bad()) nor unrelated values in the
-// same VMRegPair.
-
-// Note: the INPUTS in sig_bt are in units of Java argument words, which are
-// either 32-bit or 64-bit depending on the build. The OUTPUTS are in 32-bit
-// units regardless of build.
-
-
-// ---------------------------------------------------------------------------
-// The compiled Java calling convention. The Java convention always passes
-// 64-bit values in adjacent aligned locations (either registers or stack),
-// floats in float registers and doubles in aligned float pairs. There is
-// no backing varargs store for values in registers.
-// In the 32-bit build, longs are passed on the stack (cannot be
-// passed in I's, because longs in I's get their heads chopped off at
-// interrupt).
-int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
- VMRegPair *regs,
- int total_args_passed,
- int is_outgoing) {
- assert(F31->as_VMReg()->is_reg(), "overlapping stack/register numbers");
-
- const int int_reg_max = SPARC_ARGS_IN_REGS_NUM;
- const int flt_reg_max = 8;
-
- int int_reg = 0;
- int flt_reg = 0;
- int slot = 0;
-
- for (int i = 0; i < total_args_passed; i++) {
- switch (sig_bt[i]) {
- case T_INT:
- case T_SHORT:
- case T_CHAR:
- case T_BYTE:
- case T_BOOLEAN:
- if (int_reg < int_reg_max) {
- Register r = is_outgoing ? as_oRegister(int_reg++) : as_iRegister(int_reg++);
- regs[i].set1(r->as_VMReg());
- } else {
- regs[i].set1(VMRegImpl::stack2reg(slot++));
- }
- break;
-
- case T_LONG:
- assert((i + 1) < total_args_passed && sig_bt[i+1] == T_VOID, "expecting VOID in other half");
- // fall-through
- case T_OBJECT:
- case T_ARRAY:
- case T_ADDRESS: // Used, e.g., in slow-path locking for the lock's stack address
- if (int_reg < int_reg_max) {
- Register r = is_outgoing ? as_oRegister(int_reg++) : as_iRegister(int_reg++);
- regs[i].set2(r->as_VMReg());
- } else {
- slot = align_up(slot, 2); // align
- regs[i].set2(VMRegImpl::stack2reg(slot));
- slot += 2;
- }
- break;
-
- case T_FLOAT:
- if (flt_reg < flt_reg_max) {
- FloatRegister r = as_FloatRegister(flt_reg++);
- regs[i].set1(r->as_VMReg());
- } else {
- regs[i].set1(VMRegImpl::stack2reg(slot++));
- }
- break;
-
- case T_DOUBLE:
- assert((i + 1) < total_args_passed && sig_bt[i+1] == T_VOID, "expecting half");
- if (align_up(flt_reg, 2) + 1 < flt_reg_max) {
- flt_reg = align_up(flt_reg, 2); // align
- FloatRegister r = as_FloatRegister(flt_reg);
- regs[i].set2(r->as_VMReg());
- flt_reg += 2;
- } else {
- slot = align_up(slot, 2); // align
- regs[i].set2(VMRegImpl::stack2reg(slot));
- slot += 2;
- }
- break;
-
- case T_VOID:
- regs[i].set_bad(); // Halves of longs & doubles
- break;
-
- default:
- fatal("unknown basic type %d", sig_bt[i]);
- break;
- }
- }
-
- // retun the amount of stack space these arguments will need.
- return slot;
-}
-
-// Helper class mostly to avoid passing masm everywhere, and handle
-// store displacement overflow logic.
-class AdapterGenerator {
- MacroAssembler *masm;
- Register Rdisp;
- void set_Rdisp(Register r) { Rdisp = r; }
-
- void patch_callers_callsite();
-
- // base+st_off points to top of argument
- int arg_offset(const int st_off) { return st_off; }
- int next_arg_offset(const int st_off) {
- return st_off - Interpreter::stackElementSize;
- }
-
- // Argument slot values may be loaded first into a register because
- // they might not fit into displacement.
- RegisterOrConstant arg_slot(const int st_off);
- RegisterOrConstant next_arg_slot(const int st_off);
-
- // Stores long into offset pointed to by base
- void store_c2i_long(Register r, Register base,
- const int st_off, bool is_stack);
- void store_c2i_object(Register r, Register base,
- const int st_off);
- void store_c2i_int(Register r, Register base,
- const int st_off);
- void store_c2i_double(VMReg r_2,
- VMReg r_1, Register base, const int st_off);
- void store_c2i_float(FloatRegister f, Register base,
- const int st_off);
-
- public:
- void gen_c2i_adapter(int total_args_passed,
- // VMReg max_arg,
- int comp_args_on_stack, // VMRegStackSlots
- const BasicType *sig_bt,
- const VMRegPair *regs,
- Label& skip_fixup);
- void gen_i2c_adapter(int total_args_passed,
- // VMReg max_arg,
- int comp_args_on_stack, // VMRegStackSlots
- const BasicType *sig_bt,
- const VMRegPair *regs);
-
- AdapterGenerator(MacroAssembler *_masm) : masm(_masm) {}
-};
-
-
-// Patch the callers callsite with entry to compiled code if it exists.
-void AdapterGenerator::patch_callers_callsite() {
- Label L;
- __ ld_ptr(G5_method, in_bytes(Method::code_offset()), G3_scratch);
- __ br_null(G3_scratch, false, Assembler::pt, L);
- __ delayed()->nop();
- // Call into the VM to patch the caller, then jump to compiled callee
- __ save_frame(4); // Args in compiled layout; do not blow them
-
- // Must save all the live Gregs the list is:
- // G1: 1st Long arg (32bit build)
- // G2: global allocated to TLS
- // G3: used in inline cache check (scratch)
- // G4: 2nd Long arg (32bit build);
- // G5: used in inline cache check (Method*)
-
- // The longs must go to the stack by hand since in the 32 bit build they can be trashed by window ops.
-
- // mov(s,d)
- __ mov(G1, L1);
- __ mov(G4, L4);
- __ mov(G5_method, L5);
- __ mov(G5_method, O0); // VM needs target method
- __ mov(I7, O1); // VM needs caller's callsite
- // Must be a leaf call...
- // can be very far once the blob has been relocated
- AddressLiteral dest(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite));
- __ relocate(relocInfo::runtime_call_type);
- __ jumpl_to(dest, O7, O7);
- __ delayed()->mov(G2_thread, L7_thread_cache);
- __ mov(L7_thread_cache, G2_thread);
- __ mov(L1, G1);
- __ mov(L4, G4);
- __ mov(L5, G5_method);
-
- __ restore(); // Restore args
- __ bind(L);
-}
-
-
-RegisterOrConstant AdapterGenerator::arg_slot(const int st_off) {
- RegisterOrConstant roc(arg_offset(st_off));
- return __ ensure_simm13_or_reg(roc, Rdisp);
-}
-
-RegisterOrConstant AdapterGenerator::next_arg_slot(const int st_off) {
- RegisterOrConstant roc(next_arg_offset(st_off));
- return __ ensure_simm13_or_reg(roc, Rdisp);
-}
-
-
-// Stores long into offset pointed to by base
-void AdapterGenerator::store_c2i_long(Register r, Register base,
- const int st_off, bool is_stack) {
- // In V9, longs are given 2 64-bit slots in the interpreter, but the
- // data is passed in only 1 slot.
- __ stx(r, base, next_arg_slot(st_off));
-}
-
-void AdapterGenerator::store_c2i_object(Register r, Register base,
- const int st_off) {
- __ st_ptr (r, base, arg_slot(st_off));
-}
-
-void AdapterGenerator::store_c2i_int(Register r, Register base,
- const int st_off) {
- __ st (r, base, arg_slot(st_off));
-}
-
-// Stores into offset pointed to by base
-void AdapterGenerator::store_c2i_double(VMReg r_2,
- VMReg r_1, Register base, const int st_off) {
- // In V9, doubles are given 2 64-bit slots in the interpreter, but the
- // data is passed in only 1 slot.
- __ stf(FloatRegisterImpl::D, r_1->as_FloatRegister(), base, next_arg_slot(st_off));
-}
-
-void AdapterGenerator::store_c2i_float(FloatRegister f, Register base,
- const int st_off) {
- __ stf(FloatRegisterImpl::S, f, base, arg_slot(st_off));
-}
-
-void AdapterGenerator::gen_c2i_adapter(
- int total_args_passed,
- // VMReg max_arg,
- int comp_args_on_stack, // VMRegStackSlots
- const BasicType *sig_bt,
- const VMRegPair *regs,
- Label& L_skip_fixup) {
-
- // Before we get into the guts of the C2I adapter, see if we should be here
- // at all. We've come from compiled code and are attempting to jump to the
- // interpreter, which means the caller made a static call to get here
- // (vcalls always get a compiled target if there is one). Check for a
- // compiled target. If there is one, we need to patch the caller's call.
- // However we will run interpreted if we come thru here. The next pass
- // thru the call site will run compiled. If we ran compiled here then
- // we can (theorectically) do endless i2c->c2i->i2c transitions during
- // deopt/uncommon trap cycles. If we always go interpreted here then
- // we can have at most one and don't need to play any tricks to keep
- // from endlessly growing the stack.
- //
- // Actually if we detected that we had an i2c->c2i transition here we
- // ought to be able to reset the world back to the state of the interpreted
- // call and not bother building another interpreter arg area. We don't
- // do that at this point.
-
- patch_callers_callsite();
-
- __ bind(L_skip_fixup);
-
- // Since all args are passed on the stack, total_args_passed*wordSize is the
- // space we need. Add in varargs area needed by the interpreter. Round up
- // to stack alignment.
- const int arg_size = total_args_passed * Interpreter::stackElementSize;
- const int varargs_area =
- (frame::varargs_offset - frame::register_save_words)*wordSize;
- const int extraspace = align_up(arg_size + varargs_area, 2*wordSize);
-
- const int bias = STACK_BIAS;
- const int interp_arg_offset = frame::varargs_offset*wordSize +
- (total_args_passed-1)*Interpreter::stackElementSize;
-
- const Register base = SP;
-
- // Make some extra space on the stack.
- __ sub(SP, __ ensure_simm13_or_reg(extraspace, G3_scratch), SP);
- set_Rdisp(G3_scratch);
-
- // Write the args into the outgoing interpreter space.
- for (int i = 0; i < total_args_passed; i++) {
- const int st_off = interp_arg_offset - (i*Interpreter::stackElementSize) + bias;
- VMReg r_1 = regs[i].first();
- VMReg r_2 = regs[i].second();
- if (!r_1->is_valid()) {
- assert(!r_2->is_valid(), "");
- continue;
- }
- if (r_1->is_stack()) { // Pretend stack targets are loaded into G1
- RegisterOrConstant ld_off = reg2offset(r_1) + extraspace + bias;
- ld_off = __ ensure_simm13_or_reg(ld_off, Rdisp);
- r_1 = G1_scratch->as_VMReg();// as part of the load/store shuffle
- if (!r_2->is_valid()) __ ld (base, ld_off, G1_scratch);
- else __ ldx(base, ld_off, G1_scratch);
- }
-
- if (r_1->is_Register()) {
- Register r = r_1->as_Register()->after_restore();
- if (is_reference_type(sig_bt[i])) {
- store_c2i_object(r, base, st_off);
- } else if (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
- store_c2i_long(r, base, st_off, r_2->is_stack());
- } else {
- store_c2i_int(r, base, st_off);
- }
- } else {
- assert(r_1->is_FloatRegister(), "");
- if (sig_bt[i] == T_FLOAT) {
- store_c2i_float(r_1->as_FloatRegister(), base, st_off);
- } else {
- assert(sig_bt[i] == T_DOUBLE, "wrong type");
- store_c2i_double(r_2, r_1, base, st_off);
- }
- }
- }
-
- // Load the interpreter entry point.
- __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), G3_scratch);
-
- // Pass O5_savedSP as an argument to the interpreter.
- // The interpreter will restore SP to this value before returning.
- __ add(SP, __ ensure_simm13_or_reg(extraspace, G1), O5_savedSP);
-
- __ mov((frame::varargs_offset)*wordSize -
- 1*Interpreter::stackElementSize+bias+BytesPerWord, G1);
- // Jump to the interpreter just as if interpreter was doing it.
- __ jmpl(G3_scratch, 0, G0);
- // Setup Lesp for the call. Cannot actually set Lesp as the current Lesp
- // (really L0) is in use by the compiled frame as a generic temp. However,
- // the interpreter does not know where its args are without some kind of
- // arg pointer being passed in. Pass it in Gargs.
- __ delayed()->add(SP, G1, Gargs);
-}
-
-static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg, Register temp2_reg,
- address code_start, address code_end,
- Label& L_ok) {
- Label L_fail;
- __ set(ExternalAddress(code_start), temp_reg);
- __ set(pointer_delta(code_end, code_start, 1), temp2_reg);
- __ cmp(pc_reg, temp_reg);
- __ brx(Assembler::lessEqualUnsigned, false, Assembler::pn, L_fail);
- __ delayed()->add(temp_reg, temp2_reg, temp_reg);
- __ cmp(pc_reg, temp_reg);
- __ cmp_and_brx_short(pc_reg, temp_reg, Assembler::lessUnsigned, Assembler::pt, L_ok);
- __ bind(L_fail);
-}
-
-void AdapterGenerator::gen_i2c_adapter(int total_args_passed,
- // VMReg max_arg,
- int comp_args_on_stack, // VMRegStackSlots
- const BasicType *sig_bt,
- const VMRegPair *regs) {
- // Generate an I2C adapter: adjust the I-frame to make space for the C-frame
- // layout. Lesp was saved by the calling I-frame and will be restored on
- // return. Meanwhile, outgoing arg space is all owned by the callee
- // C-frame, so we can mangle it at will. After adjusting the frame size,
- // hoist register arguments and repack other args according to the compiled
- // code convention. Finally, end in a jump to the compiled code. The entry
- // point address is the start of the buffer.
-
- // We will only enter here from an interpreted frame and never from after
- // passing thru a c2i. Azul allowed this but we do not. If we lose the
- // race and use a c2i we will remain interpreted for the race loser(s).
- // This removes all sorts of headaches on the x86 side and also eliminates
- // the possibility of having c2i -> i2c -> c2i -> ... endless transitions.
-
- // More detail:
- // Adapters can be frameless because they do not require the caller
- // to perform additional cleanup work, such as correcting the stack pointer.
- // An i2c adapter is frameless because the *caller* frame, which is interpreted,
- // routinely repairs its own stack pointer (from interpreter_frame_last_sp),
- // even if a callee has modified the stack pointer.
- // A c2i adapter is frameless because the *callee* frame, which is interpreted,
- // routinely repairs its caller's stack pointer (from sender_sp, which is set
- // up via the senderSP register).
- // In other words, if *either* the caller or callee is interpreted, we can
- // get the stack pointer repaired after a call.
- // This is why c2i and i2c adapters cannot be indefinitely composed.
- // In particular, if a c2i adapter were to somehow call an i2c adapter,
- // both caller and callee would be compiled methods, and neither would
- // clean up the stack pointer changes performed by the two adapters.
- // If this happens, control eventually transfers back to the compiled
- // caller, but with an uncorrected stack, causing delayed havoc.
-
- if (VerifyAdapterCalls &&
- (Interpreter::code() != NULL || StubRoutines::code1() != NULL)) {
- // So, let's test for cascading c2i/i2c adapters right now.
- // assert(Interpreter::contains($return_addr) ||
- // StubRoutines::contains($return_addr),
- // "i2c adapter must return to an interpreter frame");
- __ block_comment("verify_i2c { ");
- Label L_ok;
- if (Interpreter::code() != NULL)
- range_check(masm, O7, O0, O1,
- Interpreter::code()->code_start(), Interpreter::code()->code_end(),
- L_ok);
- if (StubRoutines::code1() != NULL)
- range_check(masm, O7, O0, O1,
- StubRoutines::code1()->code_begin(), StubRoutines::code1()->code_end(),
- L_ok);
- if (StubRoutines::code2() != NULL)
- range_check(masm, O7, O0, O1,
- StubRoutines::code2()->code_begin(), StubRoutines::code2()->code_end(),
- L_ok);
- const char* msg = "i2c adapter must return to an interpreter frame";
- __ block_comment(msg);
- __ stop(msg);
- __ bind(L_ok);
- __ block_comment("} verify_i2ce ");
- }
-
- // As you can see from the list of inputs & outputs there are not a lot
- // of temp registers to work with: mostly G1, G3 & G4.
-
- // Inputs:
- // G2_thread - TLS
- // G5_method - Method oop
- // G4 (Gargs) - Pointer to interpreter's args
- // O0..O4 - free for scratch
- // O5_savedSP - Caller's saved SP, to be restored if needed
- // O6 - Current SP!
- // O7 - Valid return address
- // L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
-
- // Outputs:
- // G2_thread - TLS
- // O0-O5 - Outgoing args in compiled layout
- // O6 - Adjusted or restored SP
- // O7 - Valid return address
- // L0-L7, I0-I7 - Caller's temps (no frame pushed yet)
- // F0-F7 - more outgoing args
-
-
- // Gargs is the incoming argument base, and also an outgoing argument.
- __ sub(Gargs, BytesPerWord, Gargs);
-
- // ON ENTRY TO THE CODE WE ARE MAKING, WE HAVE AN INTERPRETED FRAME
- // WITH O7 HOLDING A VALID RETURN PC
- //
- // | |
- // : java stack :
- // | |
- // +--------------+ <--- start of outgoing args
- // | receiver | |
- // : rest of args : |---size is java-arg-words
- // | | |
- // +--------------+ <--- O4_args (misaligned) and Lesp if prior is not C2I
- // | | |
- // : unused : |---Space for max Java stack, plus stack alignment
- // | | |
- // +--------------+ <--- SP + 16*wordsize
- // | |
- // : window :
- // | |
- // +--------------+ <--- SP
-
- // WE REPACK THE STACK. We use the common calling convention layout as
- // discovered by calling SharedRuntime::calling_convention. We assume it
- // causes an arbitrary shuffle of memory, which may require some register
- // temps to do the shuffle. We hope for (and optimize for) the case where
- // temps are not needed. We may have to resize the stack slightly, in case
- // we need alignment padding (32-bit interpreter can pass longs & doubles
- // misaligned, but the compilers expect them aligned).
- //
- // | |
- // : java stack :
- // | |
- // +--------------+ <--- start of outgoing args
- // | pad, align | |
- // +--------------+ |
- // | ints, longs, | |
- // | floats, | |---Outgoing stack args.
- // : doubles : | First few args in registers.
- // | | |
- // +--------------+ <--- SP' + 16*wordsize
- // | |
- // : window :
- // | |
- // +--------------+ <--- SP'
-
- // ON EXIT FROM THE CODE WE ARE MAKING, WE STILL HAVE AN INTERPRETED FRAME
- // WITH O7 HOLDING A VALID RETURN PC - ITS JUST THAT THE ARGS ARE NOW SETUP
- // FOR COMPILED CODE AND THE FRAME SLIGHTLY GROWN.
-
- // Cut-out for having no stack args. Since up to 6 args are passed
- // in registers, we will commonly have no stack args.
- if (comp_args_on_stack > 0) {
- // Convert VMReg stack slots to words.
- int comp_words_on_stack = align_up(comp_args_on_stack*VMRegImpl::stack_slot_size, wordSize)>>LogBytesPerWord;
- // Round up to miminum stack alignment, in wordSize
- comp_words_on_stack = align_up(comp_words_on_stack, 2);
- // Now compute the distance from Lesp to SP. This calculation does not
- // include the space for total_args_passed because Lesp has not yet popped
- // the arguments.
- __ sub(SP, (comp_words_on_stack)*wordSize, SP);
- }
-
- // Now generate the shuffle code. Pick up all register args and move the
- // rest through G1_scratch.
- for (int i = 0; i < total_args_passed; i++) {
- if (sig_bt[i] == T_VOID) {
- // Longs and doubles are passed in native word order, but misaligned
- // in the 32-bit build.
- assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
- continue;
- }
-
- // Pick up 0, 1 or 2 words from Lesp+offset. Assume mis-aligned in the
- // 32-bit build and aligned in the 64-bit build. Look for the obvious
- // ldx/lddf optimizations.
-
- // Load in argument order going down.
- const int ld_off = (total_args_passed-i)*Interpreter::stackElementSize;
- set_Rdisp(G1_scratch);
-
- VMReg r_1 = regs[i].first();
- VMReg r_2 = regs[i].second();
- if (!r_1->is_valid()) {
- assert(!r_2->is_valid(), "");
- continue;
- }
- if (r_1->is_stack()) { // Pretend stack targets are loaded into F8/F9
- r_1 = F8->as_VMReg(); // as part of the load/store shuffle
- if (r_2->is_valid()) r_2 = r_1->next();
- }
- if (r_1->is_Register()) { // Register argument
- Register r = r_1->as_Register()->after_restore();
- if (!r_2->is_valid()) {
- __ ld(Gargs, arg_slot(ld_off), r);
- } else {
- // In V9, longs are given 2 64-bit slots in the interpreter, but the
- // data is passed in only 1 slot.
- RegisterOrConstant slot = (sig_bt[i] == T_LONG) ?
- next_arg_slot(ld_off) : arg_slot(ld_off);
- __ ldx(Gargs, slot, r);
- }
- } else {
- assert(r_1->is_FloatRegister(), "");
- if (!r_2->is_valid()) {
- __ ldf(FloatRegisterImpl::S, Gargs, arg_slot(ld_off), r_1->as_FloatRegister());
- } else {
- // In V9, doubles are given 2 64-bit slots in the interpreter, but the
- // data is passed in only 1 slot. This code also handles longs that
- // are passed on the stack, but need a stack-to-stack move through a
- // spare float register.
- RegisterOrConstant slot = (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) ?
- next_arg_slot(ld_off) : arg_slot(ld_off);
- __ ldf(FloatRegisterImpl::D, Gargs, slot, r_1->as_FloatRegister());
- }
- }
- // Was the argument really intended to be on the stack, but was loaded
- // into F8/F9?
- if (regs[i].first()->is_stack()) {
- assert(r_1->as_FloatRegister() == F8, "fix this code");
- // Convert stack slot to an SP offset
- int st_off = reg2offset(regs[i].first()) + STACK_BIAS;
- // Store down the shuffled stack word. Target address _is_ aligned.
- RegisterOrConstant slot = __ ensure_simm13_or_reg(st_off, Rdisp);
- if (!r_2->is_valid()) __ stf(FloatRegisterImpl::S, r_1->as_FloatRegister(), SP, slot);
- else __ stf(FloatRegisterImpl::D, r_1->as_FloatRegister(), SP, slot);
- }
- }
-
- // Jump to the compiled code just as if compiled code was doing it.
- __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3);
-#if INCLUDE_JVMCI
- if (EnableJVMCI) {
- // check if this call should be routed towards a specific entry point
- __ ld(Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), G1);
- __ cmp(G0, G1);
- Label no_alternative_target;
- __ br(Assembler::equal, false, Assembler::pn, no_alternative_target);
- __ delayed()->nop();
-
- __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()), G3);
- __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())));
-
- __ bind(no_alternative_target);
- }
-#endif // INCLUDE_JVMCI
-
- // 6243940 We might end up in handle_wrong_method if
- // the callee is deoptimized as we race thru here. If that
- // happens we don't want to take a safepoint because the
- // caller frame will look interpreted and arguments are now
- // "compiled" so it is much better to make this transition
- // invisible to the stack walking code. Unfortunately if
- // we try and find the callee by normal means a safepoint
- // is possible. So we stash the desired callee in the thread
- // and the vm will find there should this case occur.
- Address callee_target_addr(G2_thread, JavaThread::callee_target_offset());
- __ st_ptr(G5_method, callee_target_addr);
- __ jmpl(G3, 0, G0);
- __ delayed()->nop();
-}
-
-void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
- int total_args_passed,
- int comp_args_on_stack,
- const BasicType *sig_bt,
- const VMRegPair *regs) {
- AdapterGenerator agen(masm);
- agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs);
-}
-
-// ---------------------------------------------------------------
-AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
- int total_args_passed,
- // VMReg max_arg,
- int comp_args_on_stack, // VMRegStackSlots
- const BasicType *sig_bt,
- const VMRegPair *regs,
- AdapterFingerPrint* fingerprint) {
- address i2c_entry = __ pc();
-
- gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
-
-
- // -------------------------------------------------------------------------
- // Generate a C2I adapter. On entry we know G5 holds the Method*. The
- // args start out packed in the compiled layout. They need to be unpacked
- // into the interpreter layout. This will almost always require some stack
- // space. We grow the current (compiled) stack, then repack the args. We
- // finally end in a jump to the generic interpreter entry point. On exit
- // from the interpreter, the interpreter will restore our SP (lest the
- // compiled code, which relys solely on SP and not FP, get sick).
-
- address c2i_unverified_entry = __ pc();
- Label L_skip_fixup;
- {
- Register R_temp = G1; // another scratch register
-
- AddressLiteral ic_miss(SharedRuntime::get_ic_miss_stub());
-
- __ verify_oop(O0);
- __ load_klass(O0, G3_scratch);
-
- __ ld_ptr(G5_method, CompiledICHolder::holder_klass_offset(), R_temp);
- __ cmp(G3_scratch, R_temp);
-
- Label ok, ok2;
- __ brx(Assembler::equal, false, Assembler::pt, ok);
- __ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_metadata_offset(), G5_method);
- __ jump_to(ic_miss, G3_scratch);
- __ delayed()->nop();
-
- __ 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.
- __ ld_ptr(G5_method, in_bytes(Method::code_offset()), G3_scratch);
- __ bind(ok2);
- __ br_null(G3_scratch, false, Assembler::pt, L_skip_fixup);
- __ delayed()->nop();
- __ jump_to(ic_miss, G3_scratch);
- __ delayed()->nop();
-
- }
-
- address c2i_entry = __ pc();
- AdapterGenerator agen(masm);
- agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup);
-
- __ flush();
- return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
-
-}
-
-// Helper function for native calling conventions
-static VMReg int_stk_helper( int i ) {
- // Bias any stack based VMReg we get by ignoring the window area
- // but not the register parameter save area.
- //
- // This is strange for the following reasons. We'd normally expect
- // the calling convention to return an VMReg for a stack slot
- // completely ignoring any abi reserved area. C2 thinks of that
- // abi area as only out_preserve_stack_slots. This does not include
- // the area allocated by the C abi to store down integer arguments
- // because the java calling convention does not use it. So
- // since c2 assumes that there are only out_preserve_stack_slots
- // to bias the optoregs (which impacts VMRegs) when actually referencing any actual stack
- // location the c calling convention must add in this bias amount
- // to make up for the fact that the out_preserve_stack_slots is
- // insufficient for C calls. What a mess. I sure hope those 6
- // stack words were worth it on every java call!
-
- // Another way of cleaning this up would be for out_preserve_stack_slots
- // to take a parameter to say whether it was C or java calling conventions.
- // Then things might look a little better (but not much).
-
- int mem_parm_offset = i - SPARC_ARGS_IN_REGS_NUM;
- if( mem_parm_offset < 0 ) {
- return as_oRegister(i)->as_VMReg();
- } else {
- int actual_offset = (mem_parm_offset + frame::memory_parameter_word_sp_offset) * VMRegImpl::slots_per_word;
- // Now return a biased offset that will be correct when out_preserve_slots is added back in
- return VMRegImpl::stack2reg(actual_offset - SharedRuntime::out_preserve_stack_slots());
- }
-}
-
-
-int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
- VMRegPair *regs,
- VMRegPair *regs2,
- int total_args_passed) {
- assert(regs2 == NULL, "not needed on sparc");
-
- // Return the number of VMReg stack_slots needed for the args.
- // This value does not include an abi space (like register window
- // save area).
-
- // The native convention is V8 if !LP64
- // The LP64 convention is the V9 convention which is slightly more sane.
-
- // We return the amount of VMReg stack slots we need to reserve for all
- // the arguments NOT counting out_preserve_stack_slots. Since we always
- // have space for storing at least 6 registers to memory we start with that.
- // See int_stk_helper for a further discussion.
- int max_stack_slots = (frame::varargs_offset * VMRegImpl::slots_per_word) - SharedRuntime::out_preserve_stack_slots();
-
- // V9 convention: All things "as-if" on double-wide stack slots.
- // Hoist any int/ptr/long's in the first 6 to int regs.
- // Hoist any flt/dbl's in the first 16 dbl regs.
- int j = 0; // Count of actual args, not HALVES
- VMRegPair param_array_reg; // location of the argument in the parameter array
- for (int i = 0; i < total_args_passed; i++, j++) {
- param_array_reg.set_bad();
- switch (sig_bt[i]) {
- case T_BOOLEAN:
- case T_BYTE:
- case T_CHAR:
- case T_INT:
- case T_SHORT:
- regs[i].set1(int_stk_helper(j));
- break;
- case T_LONG:
- assert((i + 1) < total_args_passed && sig_bt[i+1] == T_VOID, "expecting half");
- case T_ADDRESS: // raw pointers, like current thread, for VM calls
- case T_ARRAY:
- case T_OBJECT:
- case T_METADATA:
- regs[i].set2(int_stk_helper(j));
- break;
- case T_FLOAT:
- // Per SPARC Compliance Definition 2.4.1, page 3P-12 available here
- // http://www.sparc.org/wp-content/uploads/2014/01/SCD.2.4.1.pdf.gz
- //
- // "When a callee prototype exists, and does not indicate variable arguments,
- // floating-point values assigned to locations %sp+BIAS+128 through %sp+BIAS+248
- // will be promoted to floating-point registers"
- //
- // By "promoted" it means that the argument is located in two places, an unused
- // spill slot in the "parameter array" (starts at %sp+BIAS+128), and a live
- // float register. In most cases, there are 6 or fewer arguments of any type,
- // and the standard parameter array slots (%sp+BIAS+128 to %sp+BIAS+176 exclusive)
- // serve as shadow slots. Per the spec floating point registers %d6 to %d16
- // require slots beyond that (up to %sp+BIAS+248).
- //
- {
- // V9ism: floats go in ODD registers and stack slots
- int float_index = 1 + (j << 1);
- param_array_reg.set1(VMRegImpl::stack2reg(float_index));
- if (j < 16) {
- regs[i].set1(as_FloatRegister(float_index)->as_VMReg());
- } else {
- regs[i] = param_array_reg;
- }
- }
- break;
- case T_DOUBLE:
- {
- assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half");
- // V9ism: doubles go in EVEN/ODD regs and stack slots
- int double_index = (j << 1);
- param_array_reg.set2(VMRegImpl::stack2reg(double_index));
- if (j < 16) {
- regs[i].set2(as_FloatRegister(double_index)->as_VMReg());
- } else {
- // V9ism: doubles go in EVEN/ODD stack slots
- regs[i] = param_array_reg;
- }
- }
- break;
- case T_VOID:
- regs[i].set_bad();
- j--;
- break; // Do not count HALVES
- default:
- ShouldNotReachHere();
- }
- // Keep track of the deepest parameter array slot.
- if (!param_array_reg.first()->is_valid()) {
- param_array_reg = regs[i];
- }
- if (param_array_reg.first()->is_stack()) {
- int off = param_array_reg.first()->reg2stack();
- if (off > max_stack_slots) max_stack_slots = off;
- }
- if (param_array_reg.second()->is_stack()) {
- int off = param_array_reg.second()->reg2stack();
- if (off > max_stack_slots) max_stack_slots = off;
- }
- }
- return align_up(max_stack_slots + 1, 2);
-
-}
-
-
-// ---------------------------------------------------------------------------
-void SharedRuntime::save_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) {
- switch (ret_type) {
- case T_FLOAT:
- __ stf(FloatRegisterImpl::S, F0, SP, frame_slots*VMRegImpl::stack_slot_size - 4+STACK_BIAS);
- break;
- case T_DOUBLE:
- __ stf(FloatRegisterImpl::D, F0, SP, frame_slots*VMRegImpl::stack_slot_size - 8+STACK_BIAS);
- break;
- }
-}
-
-void SharedRuntime::restore_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) {
- switch (ret_type) {
- case T_FLOAT:
- __ ldf(FloatRegisterImpl::S, SP, frame_slots*VMRegImpl::stack_slot_size - 4+STACK_BIAS, F0);
- break;
- case T_DOUBLE:
- __ ldf(FloatRegisterImpl::D, SP, frame_slots*VMRegImpl::stack_slot_size - 8+STACK_BIAS, F0);
- break;
- }
-}
-
-// Check and forward and pending exception. Thread is stored in
-// L7_thread_cache and possibly NOT in G2_thread. Since this is a native call, there
-// is no exception handler. We merely pop this frame off and throw the
-// exception in the caller's frame.
-static void check_forward_pending_exception(MacroAssembler *masm, Register Rex_oop) {
- Label L;
- __ br_null(Rex_oop, false, Assembler::pt, L);
- __ delayed()->mov(L7_thread_cache, G2_thread); // restore in case we have exception
- // Since this is a native call, we *know* the proper exception handler
- // without calling into the VM: it's the empty function. Just pop this
- // frame and then jump to forward_exception_entry; O7 will contain the
- // native caller's return PC.
- AddressLiteral exception_entry(StubRoutines::forward_exception_entry());
- __ jump_to(exception_entry, G3_scratch);
- __ delayed()->restore(); // Pop this frame off.
- __ bind(L);
-}
-
-// A simple move of integer like type
-static void simple_move32(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
- if (src.first()->is_stack()) {
- if (dst.first()->is_stack()) {
- // stack to stack
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5);
- __ st(L5, SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- // stack to reg
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
- }
- } else if (dst.first()->is_stack()) {
- // reg to stack
- __ st(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- __ mov(src.first()->as_Register(), dst.first()->as_Register());
- }
-}
-
-// On 64 bit we will store integer like items to the stack as
-// 64 bits items (sparc abi) even though java would only store
-// 32bits for a parameter. On 32bit it will simply be 32 bits
-// So this routine will do 32->32 on 32bit and 32->64 on 64bit
-static void move32_64(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
- if (src.first()->is_stack()) {
- if (dst.first()->is_stack()) {
- // stack to stack
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5);
- __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- // stack to reg
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
- }
- } else if (dst.first()->is_stack()) {
- // reg to stack
- // Some compilers (gcc) expect a clean 32 bit value on function entry
- __ signx(src.first()->as_Register(), L5);
- __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- // Some compilers (gcc) expect a clean 32 bit value on function entry
- __ signx(src.first()->as_Register(), dst.first()->as_Register());
- }
-}
-
-
-static void move_ptr(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
- if (src.first()->is_stack()) {
- if (dst.first()->is_stack()) {
- // stack to stack
- __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, L5);
- __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- // stack to reg
- __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
- }
- } else if (dst.first()->is_stack()) {
- // reg to stack
- __ st_ptr(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- __ mov(src.first()->as_Register(), dst.first()->as_Register());
- }
-}
-
-
-// An oop arg. Must pass a handle not the oop itself
-static void object_move(MacroAssembler* masm,
- OopMap* map,
- int oop_handle_offset,
- int framesize_in_slots,
- VMRegPair src,
- VMRegPair dst,
- bool is_receiver,
- int* receiver_offset) {
-
- // must pass a handle. First figure out the location we use as a handle
-
- if (src.first()->is_stack()) {
- // Oop is already on the stack
- Register rHandle = dst.first()->is_stack() ? L5 : dst.first()->as_Register();
- __ add(FP, reg2offset(src.first()) + STACK_BIAS, rHandle);
- __ ld_ptr(rHandle, 0, L4);
- __ movr( Assembler::rc_z, L4, G0, rHandle );
- if (dst.first()->is_stack()) {
- __ st_ptr(rHandle, SP, reg2offset(dst.first()) + STACK_BIAS);
- }
- int offset_in_older_frame = src.first()->reg2stack() + SharedRuntime::out_preserve_stack_slots();
- if (is_receiver) {
- *receiver_offset = (offset_in_older_frame + framesize_in_slots) * VMRegImpl::stack_slot_size;
- }
- map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + framesize_in_slots));
- } else {
- // Oop is in an input register pass we must flush it to the stack
- const Register rOop = src.first()->as_Register();
- const Register rHandle = L5;
- int oop_slot = rOop->input_number() * VMRegImpl::slots_per_word + oop_handle_offset;
- int offset = oop_slot * VMRegImpl::stack_slot_size;
- __ st_ptr(rOop, SP, offset + STACK_BIAS);
- if (is_receiver) {
- *receiver_offset = offset;
- }
- map->set_oop(VMRegImpl::stack2reg(oop_slot));
- __ add(SP, offset + STACK_BIAS, rHandle);
- __ movr( Assembler::rc_z, rOop, G0, rHandle );
-
- if (dst.first()->is_stack()) {
- __ st_ptr(rHandle, SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- __ mov(rHandle, dst.first()->as_Register());
- }
- }
-}
-
-// A float arg may have to do float reg int reg conversion
-static void float_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
- assert(!src.second()->is_valid() && !dst.second()->is_valid(), "bad float_move");
-
- if (src.first()->is_stack()) {
- if (dst.first()->is_stack()) {
- // stack to stack the easiest of the bunch
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5);
- __ st(L5, SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- // stack to reg
- if (dst.first()->is_Register()) {
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
- } else {
- __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_FloatRegister());
- }
- }
- } else if (dst.first()->is_stack()) {
- // reg to stack
- if (src.first()->is_Register()) {
- __ st(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS);
- } else {
- __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), SP, reg2offset(dst.first()) + STACK_BIAS);
- }
- } else {
- // reg to reg
- if (src.first()->is_Register()) {
- if (dst.first()->is_Register()) {
- // gpr -> gpr
- __ mov(src.first()->as_Register(), dst.first()->as_Register());
- } else {
- // gpr -> fpr
- __ st(src.first()->as_Register(), FP, -4 + STACK_BIAS);
- __ ldf(FloatRegisterImpl::S, FP, -4 + STACK_BIAS, dst.first()->as_FloatRegister());
- }
- } else if (dst.first()->is_Register()) {
- // fpr -> gpr
- __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), FP, -4 + STACK_BIAS);
- __ ld(FP, -4 + STACK_BIAS, dst.first()->as_Register());
- } else {
- // fpr -> fpr
- // In theory these overlap but the ordering is such that this is likely a nop
- if ( src.first() != dst.first()) {
- __ fmov(FloatRegisterImpl::S, src.first()->as_FloatRegister(), dst.first()->as_FloatRegister());
- }
- }
- }
-}
-
-static void split_long_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
- VMRegPair src_lo(src.first());
- VMRegPair src_hi(src.second());
- VMRegPair dst_lo(dst.first());
- VMRegPair dst_hi(dst.second());
- simple_move32(masm, src_lo, dst_lo);
- simple_move32(masm, src_hi, dst_hi);
-}
-
-// A long move
-static void long_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
-
- // Do the simple ones here else do two int moves
- if (src.is_single_phys_reg() ) {
- if (dst.is_single_phys_reg()) {
- __ mov(src.first()->as_Register(), dst.first()->as_Register());
- } else {
- // split src into two separate registers
- // Remember hi means hi address or lsw on sparc
- // Move msw to lsw
- if (dst.second()->is_reg()) {
- // MSW -> MSW
- __ srax(src.first()->as_Register(), 32, dst.first()->as_Register());
- // Now LSW -> LSW
- // this will only move lo -> lo and ignore hi
- VMRegPair split(dst.second());
- simple_move32(masm, src, split);
- } else {
- VMRegPair split(src.first(), L4->as_VMReg());
- // MSW -> MSW (lo ie. first word)
- __ srax(src.first()->as_Register(), 32, L4);
- split_long_move(masm, split, dst);
- }
- }
- } else if (dst.is_single_phys_reg()) {
- if (src.is_adjacent_aligned_on_stack(2)) {
- __ ldx(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
- } else {
- // dst is a single reg.
- // Remember lo is low address not msb for stack slots
- // and lo is the "real" register for registers
- // src is
-
- VMRegPair split;
-
- if (src.first()->is_reg()) {
- // src.lo (msw) is a reg, src.hi is stk/reg
- // we will move: src.hi (LSW) -> dst.lo, src.lo (MSW) -> src.lo [the MSW is in the LSW of the reg]
- split.set_pair(dst.first(), src.first());
- } else {
- // msw is stack move to L5
- // lsw is stack move to dst.lo (real reg)
- // we will move: src.hi (LSW) -> dst.lo, src.lo (MSW) -> L5
- split.set_pair(dst.first(), L5->as_VMReg());
- }
-
- // src.lo -> src.lo/L5, src.hi -> dst.lo (the real reg)
- // msw -> src.lo/L5, lsw -> dst.lo
- split_long_move(masm, src, split);
-
- // So dst now has the low order correct position the
- // msw half
- __ sllx(split.first()->as_Register(), 32, L5);
-
- const Register d = dst.first()->as_Register();
- __ or3(L5, d, d);
- }
- } else {
- // For LP64 we can probably do better.
- split_long_move(masm, src, dst);
- }
-}
-
-// A double move
-static void double_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
-
- // The painful thing here is that like long_move a VMRegPair might be
- // 1: a single physical register
- // 2: two physical registers (v8)
- // 3: a physical reg [lo] and a stack slot [hi] (v8)
- // 4: two stack slots
-
- // Since src is always a java calling convention we know that the src pair
- // is always either all registers or all stack (and aligned?)
-
- // in a register [lo] and a stack slot [hi]
- if (src.first()->is_stack()) {
- if (dst.first()->is_stack()) {
- // stack to stack the easiest of the bunch
- // ought to be a way to do this where if alignment is ok we use ldd/std when possible
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5);
- __ ld(FP, reg2offset(src.second()) + STACK_BIAS, L4);
- __ st(L5, SP, reg2offset(dst.first()) + STACK_BIAS);
- __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS);
- } else {
- // stack to reg
- if (dst.second()->is_stack()) {
- // stack -> reg, stack -> stack
- __ ld(FP, reg2offset(src.second()) + STACK_BIAS, L4);
- if (dst.first()->is_Register()) {
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
- } else {
- __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_FloatRegister());
- }
- // This was missing. (very rare case)
- __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS);
- } else {
- // stack -> reg
- // Eventually optimize for alignment QQQ
- if (dst.first()->is_Register()) {
- __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
- __ ld(FP, reg2offset(src.second()) + STACK_BIAS, dst.second()->as_Register());
- } else {
- __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_FloatRegister());
- __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.second()) + STACK_BIAS, dst.second()->as_FloatRegister());
- }
- }
- }
- } else if (dst.first()->is_stack()) {
- // reg to stack
- if (src.first()->is_Register()) {
- // Eventually optimize for alignment QQQ
- __ st(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS);
- if (src.second()->is_stack()) {
- __ ld(FP, reg2offset(src.second()) + STACK_BIAS, L4);
- __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS);
- } else {
- __ st(src.second()->as_Register(), SP, reg2offset(dst.second()) + STACK_BIAS);
- }
- } else {
- // fpr to stack
- if (src.second()->is_stack()) {
- ShouldNotReachHere();
- } else {
- // Is the stack aligned?
- if (reg2offset(dst.first()) & 0x7) {
- // No do as pairs
- __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), SP, reg2offset(dst.first()) + STACK_BIAS);
- __ stf(FloatRegisterImpl::S, src.second()->as_FloatRegister(), SP, reg2offset(dst.second()) + STACK_BIAS);
- } else {
- __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), SP, reg2offset(dst.first()) + STACK_BIAS);
- }
- }
- }
- } else {
- // reg to reg
- if (src.first()->is_Register()) {
- if (dst.first()->is_Register()) {
- // gpr -> gpr
- __ mov(src.first()->as_Register(), dst.first()->as_Register());
- __ mov(src.second()->as_Register(), dst.second()->as_Register());
- } else {
- // gpr -> fpr
- // ought to be able to do a single store
- __ stx(src.first()->as_Register(), FP, -8 + STACK_BIAS);
- __ stx(src.second()->as_Register(), FP, -4 + STACK_BIAS);
- // ought to be able to do a single load
- __ ldf(FloatRegisterImpl::S, FP, -8 + STACK_BIAS, dst.first()->as_FloatRegister());
- __ ldf(FloatRegisterImpl::S, FP, -4 + STACK_BIAS, dst.second()->as_FloatRegister());
- }
- } else if (dst.first()->is_Register()) {
- // fpr -> gpr
- // ought to be able to do a single store
- __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), FP, -8 + STACK_BIAS);
- // ought to be able to do a single load
- // REMEMBER first() is low address not LSB
- __ ld(FP, -8 + STACK_BIAS, dst.first()->as_Register());
- if (dst.second()->is_Register()) {
- __ ld(FP, -4 + STACK_BIAS, dst.second()->as_Register());
- } else {
- __ ld(FP, -4 + STACK_BIAS, L4);
- __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS);
- }
- } else {
- // fpr -> fpr
- // In theory these overlap but the ordering is such that this is likely a nop
- if ( src.first() != dst.first()) {
- __ fmov(FloatRegisterImpl::D, src.first()->as_FloatRegister(), dst.first()->as_FloatRegister());
- }
- }
- }
-}
-
-// Creates an inner frame if one hasn't already been created, and
-// saves a copy of the thread in L7_thread_cache
-static void create_inner_frame(MacroAssembler* masm, bool* already_created) {
- if (!*already_created) {
- __ save_frame(0);
- // Save thread in L7 (INNER FRAME); it crosses a bunch of VM calls below
- // Don't use save_thread because it smashes G2 and we merely want to save a
- // copy
- __ mov(G2_thread, L7_thread_cache);
- *already_created = true;
- }
-}
-
-
-static void save_or_restore_arguments(MacroAssembler* masm,
- const int stack_slots,
- const int total_in_args,
- const int arg_save_area,
- OopMap* map,
- VMRegPair* in_regs,
- BasicType* in_sig_bt) {
- // if map is non-NULL then the code should store the values,
- // otherwise it should load them.
- if (map != NULL) {
- // Fill in the map
- for (int i = 0; i < total_in_args; i++) {
- if (in_sig_bt[i] == T_ARRAY) {
- if (in_regs[i].first()->is_stack()) {
- int offset_in_older_frame = in_regs[i].first()->reg2stack() + SharedRuntime::out_preserve_stack_slots();
- map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + stack_slots));
- } else if (in_regs[i].first()->is_Register()) {
- map->set_oop(in_regs[i].first());
- } else {
- ShouldNotReachHere();
- }
- }
- }
- }
-
- // Save or restore double word values
- int handle_index = 0;
- for (int i = 0; i < total_in_args; i++) {
- int slot = handle_index + arg_save_area;
- int offset = slot * VMRegImpl::stack_slot_size;
- if (in_sig_bt[i] == T_LONG && in_regs[i].first()->is_Register()) {
- const Register reg = in_regs[i].first()->as_Register();
- if (reg->is_global()) {
- handle_index += 2;
- assert(handle_index <= stack_slots, "overflow");
- if (map != NULL) {
- __ stx(reg, SP, offset + STACK_BIAS);
- } else {
- __ ldx(SP, offset + STACK_BIAS, reg);
- }
- }
- } else if (in_sig_bt[i] == T_DOUBLE && in_regs[i].first()->is_FloatRegister()) {
- handle_index += 2;
- assert(handle_index <= stack_slots, "overflow");
- if (map != NULL) {
- __ stf(FloatRegisterImpl::D, in_regs[i].first()->as_FloatRegister(), SP, offset + STACK_BIAS);
- } else {
- __ ldf(FloatRegisterImpl::D, SP, offset + STACK_BIAS, in_regs[i].first()->as_FloatRegister());
- }
- }
- }
- // Save floats
- for (int i = 0; i < total_in_args; i++) {
- int slot = handle_index + arg_save_area;
- int offset = slot * VMRegImpl::stack_slot_size;
- if (in_sig_bt[i] == T_FLOAT && in_regs[i].first()->is_FloatRegister()) {
- handle_index++;
- assert(handle_index <= stack_slots, "overflow");
- if (map != NULL) {
- __ stf(FloatRegisterImpl::S, in_regs[i].first()->as_FloatRegister(), SP, offset + STACK_BIAS);
- } else {
- __ ldf(FloatRegisterImpl::S, SP, offset + STACK_BIAS, in_regs[i].first()->as_FloatRegister());
- }
- }
- }
-
-}
-
-
-// Check GCLocker::needs_gc and enter the runtime if it's true. This
-// keeps a new JNI critical region from starting until a GC has been
-// forced. Save down any oops in registers and describe them in an
-// OopMap.
-static void check_needs_gc_for_critical_native(MacroAssembler* masm,
- const int stack_slots,
- const int total_in_args,
- const int arg_save_area,
- OopMapSet* oop_maps,
- VMRegPair* in_regs,
- BasicType* in_sig_bt) {
- __ block_comment("check GCLocker::needs_gc");
- Label cont;
- AddressLiteral sync_state(GCLocker::needs_gc_address());
- __ load_bool_contents(sync_state, G3_scratch);
- __ cmp_zero_and_br(Assembler::equal, G3_scratch, cont);
- __ delayed()->nop();
-
- // Save down any values that are live in registers and call into the
- // runtime to halt for a GC
- OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/);
- save_or_restore_arguments(masm, stack_slots, total_in_args,
- arg_save_area, map, in_regs, in_sig_bt);
-
- __ mov(G2_thread, L7_thread_cache);
-
- __ set_last_Java_frame(SP, noreg);
-
- __ block_comment("block_for_jni_critical");
- __ call(CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical), relocInfo::runtime_call_type);
- __ delayed()->mov(L7_thread_cache, O0);
- oop_maps->add_gc_map( __ offset(), map);
-
- __ restore_thread(L7_thread_cache); // restore G2_thread
- __ reset_last_Java_frame();
-
- // Reload all the register arguments
- save_or_restore_arguments(masm, stack_slots, total_in_args,
- arg_save_area, NULL, in_regs, in_sig_bt);
-
- __ bind(cont);
-#ifdef ASSERT
- if (StressCriticalJNINatives) {
- // Stress register saving
- OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/);
- save_or_restore_arguments(masm, stack_slots, total_in_args,
- arg_save_area, map, in_regs, in_sig_bt);
- // Destroy argument registers
- for (int i = 0; i < total_in_args; i++) {
- if (in_regs[i].first()->is_Register()) {
- const Register reg = in_regs[i].first()->as_Register();
- if (reg->is_global()) {
- __ mov(G0, reg);
- }
- } else if (in_regs[i].first()->is_FloatRegister()) {
- __ fneg(FloatRegisterImpl::D, in_regs[i].first()->as_FloatRegister(), in_regs[i].first()->as_FloatRegister());
- }
- }
-
- save_or_restore_arguments(masm, stack_slots, total_in_args,
- arg_save_area, NULL, in_regs, in_sig_bt);
- }
-#endif
-}
-
-// Unpack an array argument into a pointer to the body and the length
-// if the array is non-null, otherwise pass 0 for both.
-static void unpack_array_argument(MacroAssembler* masm, VMRegPair reg, BasicType in_elem_type, VMRegPair body_arg, VMRegPair length_arg) {
- // Pass the length, ptr pair
- Label is_null, done;
- if (reg.first()->is_stack()) {
- VMRegPair tmp = reg64_to_VMRegPair(L2);
- // Load the arg up from the stack
- move_ptr(masm, reg, tmp);
- reg = tmp;
- }
- __ cmp(reg.first()->as_Register(), G0);
- __ brx(Assembler::equal, false, Assembler::pt, is_null);
- __ delayed()->add(reg.first()->as_Register(), arrayOopDesc::base_offset_in_bytes(in_elem_type), L4);
- move_ptr(masm, reg64_to_VMRegPair(L4), body_arg);
- __ ld(reg.first()->as_Register(), arrayOopDesc::length_offset_in_bytes(), L4);
- move32_64(masm, reg64_to_VMRegPair(L4), length_arg);
- __ ba_short(done);
- __ bind(is_null);
- // Pass zeros
- move_ptr(masm, reg64_to_VMRegPair(G0), body_arg);
- move32_64(masm, reg64_to_VMRegPair(G0), length_arg);
- __ bind(done);
-}
-
-static void verify_oop_args(MacroAssembler* masm,
- const methodHandle& method,
- const BasicType* sig_bt,
- const VMRegPair* regs) {
- Register temp_reg = G5_method; // not part of any compiled calling seq
- if (VerifyOops) {
- for (int i = 0; i < method->size_of_parameters(); i++) {
- if (is_reference_type(sig_bt[i])) {
- VMReg r = regs[i].first();
- assert(r->is_valid(), "bad oop arg");
- if (r->is_stack()) {
- RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS;
- ld_off = __ ensure_simm13_or_reg(ld_off, temp_reg);
- __ ld_ptr(SP, ld_off, temp_reg);
- __ verify_oop(temp_reg);
- } else {
- __ verify_oop(r->as_Register());
- }
- }
- }
- }
-}
-
-static void gen_special_dispatch(MacroAssembler* masm,
- const methodHandle& method,
- const BasicType* sig_bt,
- const VMRegPair* regs) {
- verify_oop_args(masm, method, sig_bt, regs);
- vmIntrinsics::ID iid = method->intrinsic_id();
-
- // Now write the args into the outgoing interpreter space
- bool has_receiver = false;
- Register receiver_reg = noreg;
- int member_arg_pos = -1;
- Register member_reg = noreg;
- int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(iid);
- if (ref_kind != 0) {
- member_arg_pos = method->size_of_parameters() - 1; // trailing MemberName argument
- member_reg = G5_method; // known to be free at this point
- has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind);
- } else if (iid == vmIntrinsics::_invokeBasic) {
- has_receiver = true;
- } else {
- fatal("unexpected intrinsic id %d", iid);
- }
-
- if (member_reg != noreg) {
- // Load the member_arg into register, if necessary.
- SharedRuntime::check_member_name_argument_is_last_argument(method, sig_bt, regs);
- VMReg r = regs[member_arg_pos].first();
- if (r->is_stack()) {
- RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS;
- ld_off = __ ensure_simm13_or_reg(ld_off, member_reg);
- __ ld_ptr(SP, ld_off, member_reg);
- } else {
- // no data motion is needed
- member_reg = r->as_Register();
- }
- }
-
- if (has_receiver) {
- // Make sure the receiver is loaded into a register.
- assert(method->size_of_parameters() > 0, "oob");
- assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object");
- VMReg r = regs[0].first();
- assert(r->is_valid(), "bad receiver arg");
- if (r->is_stack()) {
- // Porting note: This assumes that compiled calling conventions always
- // pass the receiver oop in a register. If this is not true on some
- // platform, pick a temp and load the receiver from stack.
- fatal("receiver always in a register");
- receiver_reg = G3_scratch; // known to be free at this point
- RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS;
- ld_off = __ ensure_simm13_or_reg(ld_off, member_reg);
- __ ld_ptr(SP, ld_off, receiver_reg);
- } else {
- // no data motion is needed
- receiver_reg = r->as_Register();
- }
- }
-
- // Figure out which address we are really jumping to:
- MethodHandles::generate_method_handle_dispatch(masm, iid,
- receiver_reg, member_reg, /*for_compiler_entry:*/ true);
-}
-
-// ---------------------------------------------------------------------------
-// Generate a native wrapper for a given method. The method takes arguments
-// in the Java compiled code convention, marshals them to the native
-// convention (handlizes oops, etc), transitions to native, makes the call,
-// returns to java state (possibly blocking), unhandlizes any result and
-// returns.
-//
-// Critical native functions are a shorthand for the use of
-// GetPrimtiveArrayCritical and disallow the use of any other JNI
-// functions. The wrapper is expected to unpack the arguments before
-// passing them to the callee and perform checks before and after the
-// native call to ensure that they GCLocker
-// lock_critical/unlock_critical semantics are followed. Some other
-// parts of JNI setup are skipped like the tear down of the JNI handle
-// block and the check for pending exceptions it's impossible for them
-// to be thrown.
-//
-// They are roughly structured like this:
-// if (GCLocker::needs_gc())
-// SharedRuntime::block_for_jni_critical();
-// tranistion to thread_in_native
-// unpack arrray arguments and call native entry point
-// check for safepoint in progress
-// check if any thread suspend flags are set
-// call into JVM and possible unlock the JNI critical
-// if a GC was suppressed while in the critical native.
-// transition back to thread_in_Java
-// return to caller
-//
-nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
- const methodHandle& method,
- int compile_id,
- BasicType* in_sig_bt,
- VMRegPair* in_regs,
- BasicType ret_type,
- address critical_entry) {
- if (method->is_method_handle_intrinsic()) {
- vmIntrinsics::ID iid = method->intrinsic_id();
- intptr_t start = (intptr_t)__ pc();
- int vep_offset = ((intptr_t)__ pc()) - start;
- gen_special_dispatch(masm,
- method,
- in_sig_bt,
- in_regs);
- int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period
- __ flush();
- int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually
- return nmethod::new_native_nmethod(method,
- compile_id,
- masm->code(),
- vep_offset,
- frame_complete,
- stack_slots / VMRegImpl::slots_per_word,
- in_ByteSize(-1),
- in_ByteSize(-1),
- (OopMapSet*)NULL);
- }
- bool is_critical_native = true;
- address native_func = critical_entry;
- if (native_func == NULL) {
- native_func = method->native_function();
- is_critical_native = false;
- }
- assert(native_func != NULL, "must have function");
-
- // Native nmethod wrappers never take possesion of the oop arguments.
- // So the caller will gc the arguments. The only thing we need an
- // oopMap for is if the call is static
- //
- // An OopMap for lock (and class if static), and one for the VM call itself
- OopMapSet *oop_maps = new OopMapSet();
- intptr_t start = (intptr_t)__ pc();
-
- // First thing make an ic check to see if we should even be here
- {
- Label L;
- const Register temp_reg = G3_scratch;
- AddressLiteral ic_miss(SharedRuntime::get_ic_miss_stub());
- __ verify_oop(O0);
- __ load_klass(O0, temp_reg);
- __ cmp_and_brx_short(temp_reg, G5_inline_cache_reg, Assembler::equal, Assembler::pt, L);
-
- __ jump_to(ic_miss, temp_reg);
- __ delayed()->nop();
- __ align(CodeEntryAlignment);
- __ bind(L);
- }
-
- int vep_offset = ((intptr_t)__ pc()) - start;
-
-#ifdef COMPILER1
- 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.
- // Since hashCode is usually polymorphic at call sites we can't do this
- // optimization at the call site without a lot of work.
- Label slowCase;
- Label done;
- Register obj_reg = O0;
- Register result = O0;
- Register header = G3_scratch;
- Register hash = G3_scratch; // overwrite header value with hash value
- Register mask = G1; // to get hash field from header
-
- // Unlike for Object.hashCode, System.identityHashCode is static method and
- // gets object as argument instead of the receiver.
- if (method->intrinsic_id() == vmIntrinsics::_identityHashCode) {
- assert(method->is_static(), "method should be static");
- // return 0 for null reference input
- __ br_null(obj_reg, false, Assembler::pn, done);
- __ delayed()->mov(obj_reg, hash);
- }
-
- // Read the header and build a mask to get its hash field. Give up if the object is not unlocked.
- // We depend on hash_mask being at most 32 bits and avoid the use of
- // hash_mask_in_place because it could be larger than 32 bits in a 64-bit
- // vm: see markWord.hpp.
- __ ld_ptr(obj_reg, oopDesc::mark_offset_in_bytes(), header);
- __ sethi(markWord::hash_mask, mask);
- __ btst(markWord::unlocked_value, header);
- __ br(Assembler::zero, false, Assembler::pn, slowCase);
- if (UseBiasedLocking) {
- // Check if biased and fall through to runtime if so
- __ delayed()->nop();
- __ btst(markWord::biased_lock_bit_in_place, header);
- __ br(Assembler::notZero, false, Assembler::pn, slowCase);
- }
- __ delayed()->or3(mask, markWord::hash_mask & 0x3ff, mask);
-
- // Check for a valid (non-zero) hash code and get its value.
- __ srlx(header, markWord::hash_shift, hash);
- __ andcc(hash, mask, hash);
- __ br(Assembler::equal, false, Assembler::pn, slowCase);
- __ delayed()->nop();
-
- // leaf return.
- __ bind(done);
- __ retl();
- __ delayed()->mov(hash, result);
- __ bind(slowCase);
- }
-#endif // COMPILER1
-
-
- // We have received a description of where all the java arg are located
- // on entry to the wrapper. We need to convert these args to where
- // the jni function will expect them. To figure out where they go
- // we convert the java signature to a C signature by inserting
- // the hidden arguments as arg[0] and possibly arg[1] (static method)
-
- const int total_in_args = method->size_of_parameters();
- int total_c_args = total_in_args;
- int total_save_slots = 6 * VMRegImpl::slots_per_word;
- if (!is_critical_native) {
- total_c_args += 1;
- if (method->is_static()) {
- total_c_args++;
- }
- } else {
- for (int i = 0; i < total_in_args; i++) {
- if (in_sig_bt[i] == T_ARRAY) {
- // These have to be saved and restored across the safepoint
- total_c_args++;
- }
- }
- }
-
- BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args);
- VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_c_args);
- BasicType* in_elem_bt = NULL;
-
- int argc = 0;
- if (!is_critical_native) {
- out_sig_bt[argc++] = T_ADDRESS;
- if (method->is_static()) {
- out_sig_bt[argc++] = T_OBJECT;
- }
-
- for (int i = 0; i < total_in_args ; i++ ) {
- out_sig_bt[argc++] = in_sig_bt[i];
- }
- } else {
- Thread* THREAD = Thread::current();
- in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_in_args);
- SignatureStream ss(method->signature());
- for (int i = 0; i < total_in_args ; i++ ) {
- if (in_sig_bt[i] == T_ARRAY) {
- // Arrays are passed as int, elem* pair
- out_sig_bt[argc++] = T_INT;
- out_sig_bt[argc++] = T_ADDRESS;
- ss.skip_array_prefix(1); // skip one '['
- assert(ss.is_primitive(), "primitive type expected");
- in_elem_bt[i] = ss.type();
- } else {
- out_sig_bt[argc++] = in_sig_bt[i];
- in_elem_bt[i] = T_VOID;
- }
- if (in_sig_bt[i] != T_VOID) {
- assert(in_sig_bt[i] == ss.type() ||
- in_sig_bt[i] == T_ARRAY, "must match");
- ss.next();
- }
- }
- }
-
- // Now figure out where the args must be stored and how much stack space
- // they require (neglecting out_preserve_stack_slots but space for storing
- // the 1st six register arguments). It's weird see int_stk_helper.
- //
- int out_arg_slots;
- out_arg_slots = c_calling_convention(out_sig_bt, out_regs, NULL, total_c_args);
-
- if (is_critical_native) {
- // Critical natives may have to call out so they need a save area
- // for register arguments.
- int double_slots = 0;
- int single_slots = 0;
- for ( int i = 0; i < total_in_args; i++) {
- if (in_regs[i].first()->is_Register()) {
- const Register reg = in_regs[i].first()->as_Register();
- switch (in_sig_bt[i]) {
- case T_ARRAY:
- case T_BOOLEAN:
- case T_BYTE:
- case T_SHORT:
- case T_CHAR:
- case T_INT: assert(reg->is_in(), "don't need to save these"); break;
- case T_LONG: if (reg->is_global()) double_slots++; break;
- default: ShouldNotReachHere();
- }
- } else if (in_regs[i].first()->is_FloatRegister()) {
- switch (in_sig_bt[i]) {
- case T_FLOAT: single_slots++; break;
- case T_DOUBLE: double_slots++; break;
- default: ShouldNotReachHere();
- }
- }
- }
- total_save_slots = double_slots * 2 + single_slots;
- }
-
- // Compute framesize for the wrapper. We need to handlize all oops in
- // registers. We must create space for them here that is disjoint from
- // the windowed save area because we have no control over when we might
- // flush the window again and overwrite values that gc has since modified.
- // (The live window race)
- //
- // We always just allocate 6 word for storing down these object. This allow
- // us to simply record the base and use the Ireg number to decide which
- // slot to use. (Note that the reg number is the inbound number not the
- // outbound number).
- // We must shuffle args to match the native convention, and include var-args space.
-
- // Calculate the total number of stack slots we will need.
-
- // First count the abi requirement plus all of the outgoing args
- int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots;
-
- // Now the space for the inbound oop handle area
-
- int oop_handle_offset = align_up(stack_slots, 2);
- stack_slots += total_save_slots;
-
- // Now any space we need for handlizing a klass if static method
-
- int klass_slot_offset = 0;
- int klass_offset = -1;
- int lock_slot_offset = 0;
- bool is_static = false;
-
- if (method->is_static()) {
- klass_slot_offset = stack_slots;
- stack_slots += VMRegImpl::slots_per_word;
- klass_offset = klass_slot_offset * VMRegImpl::stack_slot_size;
- is_static = true;
- }
-
- // Plus a lock if needed
-
- if (method->is_synchronized()) {
- lock_slot_offset = stack_slots;
- stack_slots += VMRegImpl::slots_per_word;
- }
-
- // Now a place to save return value or as a temporary for any gpr -> fpr moves
- stack_slots += 2;
-
- // Ok The space we have allocated will look like:
- //
- //
- // FP-> | |
- // |---------------------|
- // | 2 slots for moves |
- // |---------------------|
- // | lock box (if sync) |
- // |---------------------| <- lock_slot_offset
- // | klass (if static) |
- // |---------------------| <- klass_slot_offset
- // | oopHandle area |
- // |---------------------| <- oop_handle_offset
- // | outbound memory |
- // | based arguments |
- // | |
- // |---------------------|
- // | vararg area |
- // |---------------------|
- // | |
- // SP-> | out_preserved_slots |
- //
- //
-
-
- // Now compute actual number of stack words we need rounding to make
- // stack properly aligned.
- stack_slots = align_up(stack_slots, 2 * VMRegImpl::slots_per_word);
-
- int stack_size = stack_slots * VMRegImpl::stack_slot_size;
-
- // Generate stack overflow check before creating frame
- __ generate_stack_overflow_check(stack_size);
-
- // Generate a new frame for the wrapper.
- __ save(SP, -stack_size, SP);
-
- int frame_complete = ((intptr_t)__ pc()) - start;
-
- __ verify_thread();
-
- if (is_critical_native) {
- check_needs_gc_for_critical_native(masm, stack_slots, total_in_args,
- oop_handle_offset, oop_maps, in_regs, in_sig_bt);
- }
-
- //
- // We immediately shuffle the arguments so that any vm call we have to
- // make from here on out (sync slow path, jvmti, etc.) we will have
- // captured the oops from our caller and have a valid oopMap for
- // them.
-
- // -----------------
- // The Grand Shuffle
- //
- // Natives require 1 or 2 extra arguments over the normal ones: the JNIEnv*
- // (derived from JavaThread* which is in L7_thread_cache) and, if static,
- // the class mirror instead of a receiver. This pretty much guarantees that
- // register layout will not match. We ignore these extra arguments during
- // the shuffle. The shuffle is described by the two calling convention
- // vectors we have in our possession. We simply walk the java vector to
- // get the source locations and the c vector to get the destinations.
- // Because we have a new window and the argument registers are completely
- // disjoint ( I0 -> O1, I1 -> O2, ...) we have nothing to worry about
- // here.
-
- // This is a trick. We double the stack slots so we can claim
- // the oops in the caller's frame. Since we are sure to have
- // more args than the caller doubling is enough to make
- // sure we can capture all the incoming oop args from the
- // caller.
- //
- OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/);
- // Record sp-based slot for receiver on stack for non-static methods
- int receiver_offset = -1;
-
- // We move the arguments backward because the floating point registers
- // destination will always be to a register with a greater or equal register
- // number or the stack.
-
-#ifdef ASSERT
- bool reg_destroyed[RegisterImpl::number_of_registers];
- bool freg_destroyed[FloatRegisterImpl::number_of_registers];
- for ( int r = 0 ; r < RegisterImpl::number_of_registers ; r++ ) {
- reg_destroyed[r] = false;
- }
- for ( int f = 0 ; f < FloatRegisterImpl::number_of_registers ; f++ ) {
- freg_destroyed[f] = false;
- }
-
-#endif /* ASSERT */
-
- for ( int i = total_in_args - 1, c_arg = total_c_args - 1; i >= 0 ; i--, c_arg-- ) {
-
-#ifdef ASSERT
- if (in_regs[i].first()->is_Register()) {
- assert(!reg_destroyed[in_regs[i].first()->as_Register()->encoding()], "ack!");
- } else if (in_regs[i].first()->is_FloatRegister()) {
- assert(!freg_destroyed[in_regs[i].first()->as_FloatRegister()->encoding(FloatRegisterImpl::S)], "ack!");
- }
- if (out_regs[c_arg].first()->is_Register()) {
- reg_destroyed[out_regs[c_arg].first()->as_Register()->encoding()] = true;
- } else if (out_regs[c_arg].first()->is_FloatRegister()) {
- freg_destroyed[out_regs[c_arg].first()->as_FloatRegister()->encoding(FloatRegisterImpl::S)] = true;
- }
-#endif /* ASSERT */
-
- switch (in_sig_bt[i]) {
- case T_ARRAY:
- if (is_critical_native) {
- unpack_array_argument(masm, in_regs[i], in_elem_bt[i], out_regs[c_arg], out_regs[c_arg - 1]);
- c_arg--;
- break;
- }
- case T_OBJECT:
- assert(!is_critical_native, "no oop arguments");
- object_move(masm, map, oop_handle_offset, stack_slots, in_regs[i], out_regs[c_arg],
- ((i == 0) && (!is_static)),
- &receiver_offset);
- break;
- case T_VOID:
- break;
-
- case T_FLOAT:
- float_move(masm, in_regs[i], out_regs[c_arg]);
- break;
-
- case T_DOUBLE:
- assert( i + 1 < total_in_args &&
- in_sig_bt[i + 1] == T_VOID &&
- out_sig_bt[c_arg+1] == T_VOID, "bad arg list");
- double_move(masm, in_regs[i], out_regs[c_arg]);
- break;
-
- case T_LONG :
- long_move(masm, in_regs[i], out_regs[c_arg]);
- break;
-
- case T_ADDRESS: assert(false, "found T_ADDRESS in java args");
-
- default:
- move32_64(masm, in_regs[i], out_regs[c_arg]);
- }
- }
-
- // Pre-load a static method's oop into O1. Used both by locking code and
- // the normal JNI call code.
- if (method->is_static() && !is_critical_native) {
- __ set_oop_constant(JNIHandles::make_local(method->method_holder()->java_mirror()), O1);
-
- // Now handlize the static class mirror in O1. It's known not-null.
- __ st_ptr(O1, SP, klass_offset + STACK_BIAS);
- map->set_oop(VMRegImpl::stack2reg(klass_slot_offset));
- __ add(SP, klass_offset + STACK_BIAS, O1);
- }
-
-
- const Register L6_handle = L6;
-
- if (method->is_synchronized()) {
- assert(!is_critical_native, "unhandled");
- __ mov(O1, L6_handle);
- }
-
- // We have all of the arguments setup at this point. We MUST NOT touch any Oregs
- // except O6/O7. So if we must call out we must push a new frame. We immediately
- // push a new frame and flush the windows.
- intptr_t thepc = (intptr_t) __ pc();
- {
- address here = __ pc();
- // Call the next instruction
- __ call(here + 8, relocInfo::none);
- __ delayed()->nop();
- }
-
- // We use the same pc/oopMap repeatedly when we call out
- oop_maps->add_gc_map(thepc - start, map);
-
- // O7 now has the pc loaded that we will use when we finally call to native.
-
- // Save thread in L7; it crosses a bunch of VM calls below
- // Don't use save_thread because it smashes G2 and we merely
- // want to save a copy
- __ mov(G2_thread, L7_thread_cache);
-
-
- // If we create an inner frame once is plenty
- // when we create it we must also save G2_thread
- bool inner_frame_created = false;
-
- // dtrace method entry support
- {
- SkipIfEqual skip_if(
- masm, G3_scratch, &DTraceMethodProbes, Assembler::zero);
- // create inner frame
- __ save_frame(0);
- __ mov(G2_thread, L7_thread_cache);
- __ set_metadata_constant(method(), O1);
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry),
- G2_thread, O1);
- __ restore();
- }
-
- // RedefineClasses() tracing support for obsolete method entry
- if (log_is_enabled(Trace, redefine, class, obsolete)) {
- // create inner frame
- __ save_frame(0);
- __ mov(G2_thread, L7_thread_cache);
- __ set_metadata_constant(method(), O1);
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
- G2_thread, O1);
- __ restore();
- }
-
- // We are in the jni frame unless saved_frame is true in which case
- // we are in one frame deeper (the "inner" frame). If we are in the
- // "inner" frames the args are in the Iregs and if the jni frame then
- // they are in the Oregs.
- // If we ever need to go to the VM (for locking, jvmti) then
- // we will always be in the "inner" frame.
-
- // Lock a synchronized method
- int lock_offset = -1; // Set if locked
- if (method->is_synchronized()) {
- Register Roop = O1;
- const Register L3_box = L3;
-
- create_inner_frame(masm, &inner_frame_created);
-
- __ ld_ptr(I1, 0, O1);
- Label done;
-
- lock_offset = (lock_slot_offset * VMRegImpl::stack_slot_size);
- __ add(FP, lock_offset+STACK_BIAS, L3_box);
-#ifdef ASSERT
- if (UseBiasedLocking) {
- // making the box point to itself will make it clear it went unused
- // but also be obviously invalid
- __ st_ptr(L3_box, L3_box, 0);
- }
-#endif // ASSERT
- //
- // Compiler_lock_object (Roop, Rmark, Rbox, Rscratch) -- kills Rmark, Rbox, Rscratch
- //
- __ compiler_lock_object(Roop, L1, L3_box, L2);
- __ br(Assembler::equal, false, Assembler::pt, done);
- __ delayed() -> add(FP, lock_offset+STACK_BIAS, L3_box);
-
-
- // None of the above fast optimizations worked so we have to get into the
- // slow case of monitor enter. Inline a special case of call_VM that
- // disallows any pending_exception.
- __ mov(Roop, O0); // Need oop in O0
- __ mov(L3_box, O1);
-
- // Record last_Java_sp, in case the VM code releases the JVM lock.
-
- __ set_last_Java_frame(FP, I7);
-
- // do the call
- __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C), relocInfo::runtime_call_type);
- __ delayed()->mov(L7_thread_cache, O2);
-
- __ restore_thread(L7_thread_cache); // restore G2_thread
- __ reset_last_Java_frame();
-
-#ifdef ASSERT
- { Label L;
- __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O0);
- __ br_null_short(O0, Assembler::pt, L);
- __ stop("no pending exception allowed on exit from IR::monitorenter");
- __ bind(L);
- }
-#endif
- __ bind(done);
- }
-
-
- // Finally just about ready to make the JNI call
-
- __ flushw();
- if (inner_frame_created) {
- __ restore();
- } else {
- // Store only what we need from this frame
- // QQQ I think that non-v9 (like we care) we don't need these saves
- // either as the flush traps and the current window goes too.
- __ st_ptr(FP, SP, FP->sp_offset_in_saved_window()*wordSize + STACK_BIAS);
- __ st_ptr(I7, SP, I7->sp_offset_in_saved_window()*wordSize + STACK_BIAS);
- }
-
- // get JNIEnv* which is first argument to native
- if (!is_critical_native) {
- __ add(G2_thread, in_bytes(JavaThread::jni_environment_offset()), O0);
- }
-
- // Use that pc we placed in O7 a while back as the current frame anchor
- __ set_last_Java_frame(SP, O7);
-
- // We flushed the windows ages ago now mark them as flushed before transitioning.
- __ set(JavaFrameAnchor::flushed, G3_scratch);
- __ st(G3_scratch, G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset());
-
- // Transition from _thread_in_Java to _thread_in_native.
- __ set(_thread_in_native, G3_scratch);
-
- AddressLiteral dest(native_func);
- __ relocate(relocInfo::runtime_call_type);
- __ jumpl_to(dest, O7, O7);
- __ delayed()->st(G3_scratch, G2_thread, JavaThread::thread_state_offset());
-
- __ restore_thread(L7_thread_cache); // restore G2_thread
-
- // Unpack native results. For int-types, we do any needed sign-extension
- // and move things into I0. The return value there will survive any VM
- // calls for blocking or unlocking. An FP or OOP result (handle) is done
- // specially in the slow-path code.
- switch (ret_type) {
- case T_VOID: break; // Nothing to do!
- case T_FLOAT: break; // Got it where we want it (unless slow-path)
- case T_DOUBLE: break; // Got it where we want it (unless slow-path)
- // In 64 bits build result is in O0, in O0, O1 in 32bit build
- case T_LONG:
- // Fall thru
- case T_OBJECT: // Really a handle
- case T_ARRAY:
- case T_INT:
- __ mov(O0, I0);
- break;
- case T_BOOLEAN: __ subcc(G0, O0, G0); __ addc(G0, 0, I0); break; // !0 => true; 0 => false
- case T_BYTE : __ sll(O0, 24, O0); __ sra(O0, 24, I0); break;
- case T_CHAR : __ sll(O0, 16, O0); __ srl(O0, 16, I0); break; // cannot use and3, 0xFFFF too big as immediate value!
- case T_SHORT : __ sll(O0, 16, O0); __ sra(O0, 16, I0); break;
- break; // Cannot de-handlize until after reclaiming jvm_lock
- default:
- ShouldNotReachHere();
- }
-
- Label after_transition;
- // must we block?
-
- // Block, if necessary, before resuming in _thread_in_Java state.
- // In order for GC to work, don't clear the last_Java_sp until after blocking.
- { Label no_block;
-
- // Switch thread to "native transition" state before reading the synchronization state.
- // This additional state is necessary because reading and testing the synchronization
- // state is not atomic w.r.t. GC, as this scenario demonstrates:
- // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted.
- // VM thread changes sync state to synchronizing and suspends threads for GC.
- // Thread A is resumed to finish this native method, but doesn't block here since it
- // didn't see any synchronization is progress, and escapes.
- __ set(_thread_in_native_trans, G3_scratch);
- __ st(G3_scratch, G2_thread, JavaThread::thread_state_offset());
-
- // Force this write out before the read below
- __ membar(Assembler::StoreLoad);
-
- Label L;
- Address suspend_state(G2_thread, JavaThread::suspend_flags_offset());
- __ safepoint_poll(L, false, G2_thread, G3_scratch);
- __ delayed()->ld(suspend_state, G3_scratch);
- __ cmp_and_br_short(G3_scratch, 0, Assembler::equal, Assembler::pt, no_block);
- __ bind(L);
-
- // Block. Save any potential method result value before the operation and
- // use a leaf call to leave the last_Java_frame setup undisturbed. Doing this
- // lets us share the oopMap we used when we went native rather the create
- // a distinct one for this pc
- //
- save_native_result(masm, ret_type, stack_slots);
- if (!is_critical_native) {
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
- G2_thread);
- } else {
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans_and_transition),
- G2_thread);
- }
-
- // Restore any method result value
- restore_native_result(masm, ret_type, stack_slots);
-
- if (is_critical_native) {
- // The call above performed the transition to thread_in_Java so
- // skip the transition logic below.
- __ ba(after_transition);
- __ delayed()->nop();
- }
-
- __ bind(no_block);
- }
-
- // thread state is thread_in_native_trans. Any safepoint blocking has already
- // happened so we can now change state to _thread_in_Java.
- __ set(_thread_in_Java, G3_scratch);
- __ st(G3_scratch, G2_thread, JavaThread::thread_state_offset());
- __ bind(after_transition);
-
- Label no_reguard;
- __ ld(G2_thread, JavaThread::stack_guard_state_offset(), G3_scratch);
- __ cmp_and_br_short(G3_scratch, JavaThread::stack_guard_yellow_reserved_disabled, Assembler::notEqual, Assembler::pt, no_reguard);
-
- save_native_result(masm, ret_type, stack_slots);
- __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages));
- __ delayed()->nop();
-
- __ restore_thread(L7_thread_cache); // restore G2_thread
- restore_native_result(masm, ret_type, stack_slots);
-
- __ bind(no_reguard);
-
- // Handle possible exception (will unlock if necessary)
-
- // native result if any is live in freg or I0 (and I1 if long and 32bit vm)
-
- // Unlock
- if (method->is_synchronized()) {
- Label done;
- Register I2_ex_oop = I2;
- const Register L3_box = L3;
- // Get locked oop from the handle we passed to jni
- __ ld_ptr(L6_handle, 0, L4);
- __ add(SP, lock_offset+STACK_BIAS, L3_box);
- // Must save pending exception around the slow-path VM call. Since it's a
- // leaf call, the pending exception (if any) can be kept in a register.
- __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), I2_ex_oop);
- // Now unlock
- // (Roop, Rmark, Rbox, Rscratch)
- __ compiler_unlock_object(L4, L1, L3_box, L2);
- __ br(Assembler::equal, false, Assembler::pt, done);
- __ delayed()-> add(SP, lock_offset+STACK_BIAS, L3_box);
-
- // save and restore any potential method result value around the unlocking
- // operation. Will save in I0 (or stack for FP returns).
- save_native_result(masm, ret_type, stack_slots);
-
- // Must clear pending-exception before re-entering the VM. Since this is
- // a leaf call, pending-exception-oop can be safely kept in a register.
- __ st_ptr(G0, G2_thread, in_bytes(Thread::pending_exception_offset()));
-
- // slow case of monitor enter. Inline a special case of call_VM that
- // disallows any pending_exception.
- __ mov(L3_box, O1);
-
- // Pass in current thread pointer
- __ mov(G2_thread, O2);
-
- __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C), relocInfo::runtime_call_type);
- __ delayed()->mov(L4, O0); // Need oop in O0
-
- __ restore_thread(L7_thread_cache); // restore G2_thread
-
-#ifdef ASSERT
- { Label L;
- __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O0);
- __ br_null_short(O0, Assembler::pt, L);
- __ stop("no pending exception allowed on exit from IR::monitorexit");
- __ bind(L);
- }
-#endif
- restore_native_result(masm, ret_type, stack_slots);
- // check_forward_pending_exception jump to forward_exception if any pending
- // exception is set. The forward_exception routine expects to see the
- // exception in pending_exception and not in a register. Kind of clumsy,
- // since all folks who branch to forward_exception must have tested
- // pending_exception first and hence have it in a register already.
- __ st_ptr(I2_ex_oop, G2_thread, in_bytes(Thread::pending_exception_offset()));
- __ bind(done);
- }
-
- // Tell dtrace about this method exit
- {
- SkipIfEqual skip_if(
- masm, G3_scratch, &DTraceMethodProbes, Assembler::zero);
- save_native_result(masm, ret_type, stack_slots);
- __ set_metadata_constant(method(), O1);
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit),
- G2_thread, O1);
- restore_native_result(masm, ret_type, stack_slots);
- }
-
- // Clear "last Java frame" SP and PC.
- __ verify_thread(); // G2_thread must be correct
- __ reset_last_Java_frame();
-
- // Unbox oop result, e.g. JNIHandles::resolve value in I0.
- if (is_reference_type(ret_type)) {
- __ resolve_jobject(I0, G3_scratch);
- }
-
- if (CheckJNICalls) {
- // clear_pending_jni_exception_check
- __ st_ptr(G0, G2_thread, JavaThread::pending_jni_exception_check_fn_offset());
- }
-
- if (!is_critical_native) {
- // reset handle block
- __ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), L5);
- __ st(G0, L5, JNIHandleBlock::top_offset_in_bytes());
-
- __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), G3_scratch);
- check_forward_pending_exception(masm, G3_scratch);
- }
-
-
- // Return
-
- __ ret();
- __ delayed()->restore();
-
- __ flush();
-
- nmethod *nm = nmethod::new_native_nmethod(method,
- compile_id,
- masm->code(),
- vep_offset,
- frame_complete,
- stack_slots / VMRegImpl::slots_per_word,
- (is_static ? in_ByteSize(klass_offset) : in_ByteSize(receiver_offset)),
- in_ByteSize(lock_offset),
- oop_maps);
-
- if (is_critical_native) {
- nm->set_lazy_critical_native(true);
- }
- return nm;
-
-}
-
-// this function returns the adjust size (in number of words) to a c2i adapter
-// activation for use during deoptimization
-int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) {
- assert(callee_locals >= callee_parameters,
- "test and remove; got more parms than locals");
- if (callee_locals < callee_parameters)
- return 0; // No adjustment for negative locals
- int diff = (callee_locals - callee_parameters) * Interpreter::stackElementWords;
- return align_up(diff, WordsPerLong);
-}
-
-// "Top of Stack" slots that may be unused by the calling convention but must
-// otherwise be preserved.
-// On Intel these are not necessary and the value can be zero.
-// On Sparc this describes the words reserved for storing a register window
-// when an interrupt occurs.
-uint SharedRuntime::out_preserve_stack_slots() {
- return frame::register_save_words * VMRegImpl::slots_per_word;
-}
-
-static void gen_new_frame(MacroAssembler* masm, bool deopt) {
-//
-// Common out the new frame generation for deopt and uncommon trap
-//
- Register G3pcs = G3_scratch; // Array of new pcs (input)
- Register Oreturn0 = O0;
- Register Oreturn1 = O1;
- Register O2UnrollBlock = O2;
- Register O3array = O3; // Array of frame sizes (input)
- Register O4array_size = O4; // number of frames (input)
- Register O7frame_size = O7; // number of frames (input)
-
- __ ld_ptr(O3array, 0, O7frame_size);
- __ sub(G0, O7frame_size, O7frame_size);
- __ save(SP, O7frame_size, SP);
- __ ld_ptr(G3pcs, 0, I7); // load frame's new pc
-
- #ifdef ASSERT
- // make sure that the frames are aligned properly
- #endif
-
- // Deopt needs to pass some extra live values from frame to frame
-
- if (deopt) {
- __ mov(Oreturn0->after_save(), Oreturn0);
- __ mov(Oreturn1->after_save(), Oreturn1);
- }
-
- __ mov(O4array_size->after_save(), O4array_size);
- __ sub(O4array_size, 1, O4array_size);
- __ mov(O3array->after_save(), O3array);
- __ mov(O2UnrollBlock->after_save(), O2UnrollBlock);
- __ add(G3pcs, wordSize, G3pcs); // point to next pc value
-
- #ifdef ASSERT
- // trash registers to show a clear pattern in backtraces
- __ set(0xDEAD0000, I0);
- __ add(I0, 2, I1);
- __ add(I0, 4, I2);
- __ add(I0, 6, I3);
- __ add(I0, 8, I4);
- // Don't touch I5 could have valuable savedSP
- __ set(0xDEADBEEF, L0);
- __ mov(L0, L1);
- __ mov(L0, L2);
- __ mov(L0, L3);
- __ mov(L0, L4);
- __ mov(L0, L5);
-
- // trash the return value as there is nothing to return yet
- __ set(0xDEAD0001, O7);
- #endif
-
- __ mov(SP, O5_savedSP);
-}
-
-
-static void make_new_frames(MacroAssembler* masm, bool deopt) {
- //
- // loop through the UnrollBlock info and create new frames
- //
- Register G3pcs = G3_scratch;
- Register Oreturn0 = O0;
- Register Oreturn1 = O1;
- Register O2UnrollBlock = O2;
- Register O3array = O3;
- Register O4array_size = O4;
- Label loop;
-
-#ifdef ASSERT
- // Compilers generate code that bang the stack by as much as the
- // interpreter would need. So this stack banging should never
- // trigger a fault. Verify that it does not on non product builds.
- if (UseStackBanging) {
- // Get total frame size for interpreted frames
- __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes(), O4);
- __ bang_stack_size(O4, O3, G3_scratch);
- }
-#endif
-
- __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::number_of_frames_offset_in_bytes(), O4array_size);
- __ ld_ptr(O2UnrollBlock, Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes(), G3pcs);
- __ ld_ptr(O2UnrollBlock, Deoptimization::UnrollBlock::frame_sizes_offset_in_bytes(), O3array);
-
- // Adjust old interpreter frame to make space for new frame's extra java locals
- //
- // We capture the original sp for the transition frame only because it is needed in
- // order to properly calculate interpreter_sp_adjustment. Even though in real life
- // every interpreter frame captures a savedSP it is only needed at the transition
- // (fortunately). If we had to have it correct everywhere then we would need to
- // be told the sp_adjustment for each frame we create. If the frame size array
- // were to have twice the frame count entries then we could have pairs [sp_adjustment, frame_size]
- // for each frame we create and keep up the illusion every where.
- //
-
- __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::caller_adjustment_offset_in_bytes(), O7);
- __ mov(SP, O5_savedSP); // remember initial sender's original sp before adjustment
- __ sub(SP, O7, SP);
-
-#ifdef ASSERT
- // make sure that there is at least one entry in the array
- __ tst(O4array_size);
- __ breakpoint_trap(Assembler::zero, Assembler::icc);
-#endif
-
- // Now push the new interpreter frames
- __ bind(loop);
-
- // allocate a new frame, filling the registers
-
- gen_new_frame(masm, deopt); // allocate an interpreter frame
-
- __ cmp_zero_and_br(Assembler::notZero, O4array_size, loop);
- __ delayed()->add(O3array, wordSize, O3array);
- __ ld_ptr(G3pcs, 0, O7); // load final frame new pc
-
-}
-
-//------------------------------generate_deopt_blob----------------------------
-// Ought to generate an ideal graph & compile, but here's some SPARC ASM
-// instead.
-void SharedRuntime::generate_deopt_blob() {
- // allocate space for the code
- ResourceMark rm;
- // setup code generation tools
- int pad = VerifyThread ? 512 : 0;// Extra slop space for more verify code
-#ifdef ASSERT
- if (UseStackBanging) {
- pad += (JavaThread::stack_shadow_zone_size() / os::vm_page_size())*16 + 32;
- }
-#endif
-#if INCLUDE_JVMCI
- if (EnableJVMCI) {
- pad += 1000; // Increase the buffer size when compiling for JVMCI
- }
-#endif
- CodeBuffer buffer("deopt_blob", 2100+pad, 512);
- MacroAssembler* masm = new MacroAssembler(&buffer);
- FloatRegister Freturn0 = F0;
- Register Greturn1 = G1;
- Register Oreturn0 = O0;
- Register Oreturn1 = O1;
- Register O2UnrollBlock = O2;
- Register L0deopt_mode = L0;
- Register G4deopt_mode = G4_scratch;
- int frame_size_words;
- Address saved_Freturn0_addr(FP, -sizeof(double) + STACK_BIAS);
- Label cont;
-
- OopMapSet *oop_maps = new OopMapSet();
-
- //
- // This is the entry point for code which is returning to a de-optimized
- // frame.
- // The steps taken by this frame are as follows:
- // - push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1)
- // and all potentially live registers (at a pollpoint many registers can be live).
- //
- // - call the C routine: Deoptimization::fetch_unroll_info (this function
- // returns information about the number and size of interpreter frames
- // which are equivalent to the frame which is being deoptimized)
- // - deallocate the unpack frame, restoring only results values. Other
- // volatile registers will now be captured in the vframeArray as needed.
- // - deallocate the deoptimization frame
- // - in a loop using the information returned in the previous step
- // push new interpreter frames (take care to propagate the return
- // values through each new frame pushed)
- // - create a dummy "unpack_frame" and save the return values (O0, O1, F0)
- // - call the C routine: Deoptimization::unpack_frames (this function
- // lays out values on the interpreter frame which was just created)
- // - deallocate the dummy unpack_frame
- // - ensure that all the return values are correctly set and then do
- // a return to the interpreter entry point
- //
- // Refer to the following methods for more information:
- // - Deoptimization::fetch_unroll_info
- // - Deoptimization::unpack_frames
-
- OopMap* map = NULL;
-
- int start = __ offset();
-
- // restore G2, the trampoline destroyed it
- __ get_thread();
-
- // On entry we have been called by the deoptimized nmethod with a call that
- // replaced the original call (or safepoint polling location) so the deoptimizing
- // pc is now in O7. Return values are still in the expected places
-
- map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
- __ ba(cont);
- __ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode);
-
-
-#if INCLUDE_JVMCI
- Label after_fetch_unroll_info_call;
- int implicit_exception_uncommon_trap_offset = 0;
- int uncommon_trap_offset = 0;
-
- if (EnableJVMCI) {
- masm->block_comment("BEGIN implicit_exception_uncommon_trap");
- implicit_exception_uncommon_trap_offset = __ offset() - start;
-
- __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()), O7);
- __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())));
- __ add(O7, -8, O7);
-
- uncommon_trap_offset = __ offset() - start;
-
- // Save everything in sight.
- (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
- __ set_last_Java_frame(SP, NULL);
-
- __ ld(G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()), O1);
- __ sub(G0, 1, L1);
- __ st(L1, G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()));
-
- __ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode);
- __ mov(G2_thread, O0);
- __ mov(L0deopt_mode, O2);
- __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap));
- __ delayed()->nop();
- oop_maps->add_gc_map( __ offset()-start, map->deep_copy());
- __ get_thread();
- __ add(O7, 8, O7);
- __ reset_last_Java_frame();
-
- __ ba(after_fetch_unroll_info_call);
- __ delayed()->nop(); // Delay slot
- masm->block_comment("END implicit_exception_uncommon_trap");
- } // EnableJVMCI
-#endif // INCLUDE_JVMCI
-
- int exception_offset = __ offset() - start;
-
- // restore G2, the trampoline destroyed it
- __ get_thread();
-
- // On entry we have been jumped to by the exception handler (or exception_blob
- // for server). O0 contains the exception oop and O7 contains the original
- // exception pc. So if we push a frame here it will look to the
- // stack walking code (fetch_unroll_info) just like a normal call so
- // state will be extracted normally.
-
- // save exception oop in JavaThread and fall through into the
- // exception_in_tls case since they are handled in same way except
- // for where the pending exception is kept.
- __ st_ptr(Oexception, G2_thread, JavaThread::exception_oop_offset());
-
- //
- // Vanilla deoptimization with an exception pending in exception_oop
- //
- int exception_in_tls_offset = __ offset() - start;
-
- // No need to update oop_map as each call to save_live_registers will produce identical oopmap
- // Opens a new stack frame
- (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
-
- // Restore G2_thread
- __ get_thread();
-
-#ifdef ASSERT
- {
- // verify that there is really an exception oop in exception_oop
- Label has_exception;
- __ ld_ptr(G2_thread, JavaThread::exception_oop_offset(), Oexception);
- __ br_notnull_short(Oexception, Assembler::pt, has_exception);
- __ stop("no exception in thread");
- __ bind(has_exception);
-
- // verify that there is no pending exception
- Label no_pending_exception;
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- __ ld_ptr(exception_addr, Oexception);
- __ br_null_short(Oexception, Assembler::pt, no_pending_exception);
- __ stop("must not have pending exception here");
- __ bind(no_pending_exception);
- }
-#endif
-
- __ ba(cont);
- __ delayed()->mov(Deoptimization::Unpack_exception, L0deopt_mode);;
-
- //
- // Reexecute entry, similar to c2 uncommon trap
- //
- int reexecute_offset = __ offset() - start;
-#if INCLUDE_JVMCI && !defined(COMPILER1)
- if (EnableJVMCI && UseJVMCICompiler) {
- // JVMCI does not use this kind of deoptimization
- __ should_not_reach_here();
- }
-#endif
- // No need to update oop_map as each call to save_live_registers will produce identical oopmap
- (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
-
- __ mov(Deoptimization::Unpack_reexecute, L0deopt_mode);
-
- __ bind(cont);
-
- __ set_last_Java_frame(SP, noreg);
-
- // do the call by hand so we can get the oopmap
-
- __ mov(G2_thread, L7_thread_cache);
- __ mov(L0deopt_mode, O1);
- __ call(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), relocInfo::runtime_call_type);
- __ delayed()->mov(G2_thread, O0);
-
- // Set an oopmap for the call site this describes all our saved volatile registers
-
- oop_maps->add_gc_map( __ offset()-start, map);
-
- __ mov(L7_thread_cache, G2_thread);
-
- __ reset_last_Java_frame();
-
-#if INCLUDE_JVMCI
- if (EnableJVMCI) {
- __ bind(after_fetch_unroll_info_call);
- }
-#endif
- // NOTE: we know that only O0/O1 will be reloaded by restore_result_registers
- // so this move will survive
-
- __ mov(L0deopt_mode, G4deopt_mode);
-
- __ mov(O0, O2UnrollBlock->after_save());
-
- RegisterSaver::restore_result_registers(masm);
-
- __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), G4deopt_mode);
- Label noException;
- __ cmp_and_br_short(G4deopt_mode, Deoptimization::Unpack_exception, Assembler::notEqual, Assembler::pt, noException);
-
- // Move the pending exception from exception_oop to Oexception so
- // the pending exception will be picked up the interpreter.
- __ ld_ptr(G2_thread, in_bytes(JavaThread::exception_oop_offset()), Oexception);
- __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_oop_offset()));
- __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_pc_offset()));
- __ bind(noException);
-
- // deallocate the deoptimization frame taking care to preserve the return values
- __ mov(Oreturn0, Oreturn0->after_save());
- __ mov(Oreturn1, Oreturn1->after_save());
- __ mov(O2UnrollBlock, O2UnrollBlock->after_save());
- __ restore();
-
- // Allocate new interpreter frame(s) and possible c2i adapter frame
-
- make_new_frames(masm, true);
-
- // push a dummy "unpack_frame" taking care of float return values and
- // call Deoptimization::unpack_frames to have the unpacker layout
- // information in the interpreter frames just created and then return
- // to the interpreter entry point
- __ save(SP, -frame_size_words*wordSize, SP);
- __ stf(FloatRegisterImpl::D, Freturn0, saved_Freturn0_addr);
- // LP64 uses g4 in set_last_Java_frame
- __ mov(G4deopt_mode, O1);
- __ set_last_Java_frame(SP, G0);
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, O1);
- __ reset_last_Java_frame();
- __ ldf(FloatRegisterImpl::D, saved_Freturn0_addr, Freturn0);
-
- __ ret();
- __ delayed()->restore();
-
- masm->flush();
- _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_words);
- _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
-#if INCLUDE_JVMCI
- if (EnableJVMCI) {
- _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
- _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
- }
-#endif
-}
-
-#ifdef COMPILER2
-
-//------------------------------generate_uncommon_trap_blob--------------------
-// Ought to generate an ideal graph & compile, but here's some SPARC ASM
-// instead.
-void SharedRuntime::generate_uncommon_trap_blob() {
- // allocate space for the code
- ResourceMark rm;
- // setup code generation tools
- int pad = VerifyThread ? 512 : 0;
-#ifdef ASSERT
- if (UseStackBanging) {
- pad += (JavaThread::stack_shadow_zone_size() / os::vm_page_size())*16 + 32;
- }
-#endif
- CodeBuffer buffer("uncommon_trap_blob", 2700+pad, 512);
- MacroAssembler* masm = new MacroAssembler(&buffer);
- Register O2UnrollBlock = O2;
- Register O2klass_index = O2;
-
- //
- // This is the entry point for all traps the compiler takes when it thinks
- // it cannot handle further execution of compilation code. The frame is
- // deoptimized in these cases and converted into interpreter frames for
- // execution
- // The steps taken by this frame are as follows:
- // - push a fake "unpack_frame"
- // - call the C routine Deoptimization::uncommon_trap (this function
- // packs the current compiled frame into vframe arrays and returns
- // information about the number and size of interpreter frames which
- // are equivalent to the frame which is being deoptimized)
- // - deallocate the "unpack_frame"
- // - deallocate the deoptimization frame
- // - in a loop using the information returned in the previous step
- // push interpreter frames;
- // - create a dummy "unpack_frame"
- // - call the C routine: Deoptimization::unpack_frames (this function
- // lays out values on the interpreter frame which was just created)
- // - deallocate the dummy unpack_frame
- // - return to the interpreter entry point
- //
- // Refer to the following methods for more information:
- // - Deoptimization::uncommon_trap
- // - Deoptimization::unpack_frame
-
- // the unloaded class index is in O0 (first parameter to this blob)
-
- // push a dummy "unpack_frame"
- // and call Deoptimization::uncommon_trap to pack the compiled frame into
- // vframe array and return the UnrollBlock information
- __ save_frame(0);
- __ set_last_Java_frame(SP, noreg);
- __ mov(I0, O2klass_index);
- __ mov(Deoptimization::Unpack_uncommon_trap, O3); // exec mode
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), G2_thread, O2klass_index, O3);
- __ reset_last_Java_frame();
- __ mov(O0, O2UnrollBlock->after_save());
- __ restore();
-
- // deallocate the deoptimized frame taking care to preserve the return values
- __ mov(O2UnrollBlock, O2UnrollBlock->after_save());
- __ restore();
-
-#ifdef ASSERT
- { Label L;
- __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), O1);
- __ cmp_and_br_short(O1, Deoptimization::Unpack_uncommon_trap, Assembler::equal, Assembler::pt, L);
- __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap");
- __ bind(L);
- }
-#endif
-
- // Allocate new interpreter frame(s) and possible c2i adapter frame
-
- make_new_frames(masm, false);
-
- // push a dummy "unpack_frame" taking care of float return values and
- // call Deoptimization::unpack_frames to have the unpacker layout
- // information in the interpreter frames just created and then return
- // to the interpreter entry point
- __ save_frame(0);
- __ set_last_Java_frame(SP, noreg);
- __ mov(Deoptimization::Unpack_uncommon_trap, O3); // indicate it is the uncommon trap case
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, O3);
- __ reset_last_Java_frame();
- __ ret();
- __ delayed()->restore();
-
- masm->flush();
- _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, NULL, __ total_frame_size_in_bytes(0)/wordSize);
-}
-
-#endif // COMPILER2
-
-//------------------------------generate_handler_blob-------------------
-//
-// Generate a special Compile2Runtime blob that saves all registers, and sets
-// up an OopMap.
-//
-// This blob is jumped to (via a breakpoint and the signal handler) from a
-// safepoint in compiled code. On entry to this blob, O7 contains the
-// address in the original nmethod at which we should resume normal execution.
-// Thus, this blob looks like a subroutine which must preserve lots of
-// registers and return normally. Note that O7 is never register-allocated,
-// so it is guaranteed to be free here.
-//
-
-// The hardest part of what this blob must do is to save the 64-bit %o
-// registers in the 32-bit build. A simple 'save' turn the %o's to %i's and
-// an interrupt will chop off their heads. Making space in the caller's frame
-// first will let us save the 64-bit %o's before save'ing, but we cannot hand
-// the adjusted FP off to the GC stack-crawler: this will modify the caller's
-// SP and mess up HIS OopMaps. So we first adjust the caller's SP, then save
-// the 64-bit %o's, then do a save, then fixup the caller's SP (our FP).
-// Tricky, tricky, tricky...
-
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
- assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before");
-
- // allocate space for the code
- ResourceMark rm;
- // setup code generation tools
- // Measured 8/7/03 at 896 in 32bit debug build (no VerifyThread)
- // Measured 8/7/03 at 1080 in 32bit debug build (VerifyThread)
- CodeBuffer buffer("handler_blob", 1600, 512);
- MacroAssembler* masm = new MacroAssembler(&buffer);
- int frame_size_words;
- OopMapSet *oop_maps = new OopMapSet();
- OopMap* map = NULL;
-
- int start = __ offset();
-
- bool cause_return = (poll_type == POLL_AT_RETURN);
- // If this causes a return before the processing, then do a "restore"
- if (cause_return) {
- __ restore();
- } else {
- // Make it look like we were called via the poll
- // so that frame constructor always sees a valid return address
- __ ld_ptr(Address(G2_thread, JavaThread::saved_exception_pc_offset()), O7);
- __ sub(O7, frame::pc_return_offset, O7);
- }
-
- map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
-
- // setup last_Java_sp (blows G4)
- __ set_last_Java_frame(SP, noreg);
-
- Register saved_O7 = O7->after_save();
- if (!cause_return) {
- // Keep a copy of the return pc in L0 to detect if it gets modified
- __ mov(saved_O7, L0);
- // Adjust and keep a copy of our npc saved by the signal handler
- __ ld_ptr(Address(G2_thread, JavaThread::saved_exception_npc_offset()), L1);
- __ sub(L1, frame::pc_return_offset, L1);
- }
-
- // call into the runtime to handle illegal instructions exception
- // Do not use call_VM_leaf, because we need to make a GC map at this call site.
- __ mov(G2_thread, O0);
- __ save_thread(L7_thread_cache);
- __ call(call_ptr);
- __ delayed()->nop();
-
- // Set an oopmap for the call site.
- // We need this not only for callee-saved registers, but also for volatile
- // registers that the compiler might be keeping live across a safepoint.
-
- oop_maps->add_gc_map( __ offset() - start, map);
-
- __ restore_thread(L7_thread_cache);
- // clear last_Java_sp
- __ reset_last_Java_frame();
-
- // Check for exceptions
- Label pending;
-
- __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O1);
- __ br_notnull_short(O1, Assembler::pn, pending);
-
- if (!cause_return) {
- // If nobody modified our return pc then we must return to the npc which he saved in L1
- __ cmp(saved_O7, L0);
- __ movcc(Assembler::equal, false, Assembler::ptr_cc, L1, saved_O7);
- }
-
- RegisterSaver::restore_live_registers(masm);
-
- // We are back the the original state on entry and ready to go.
-
- __ retl();
- __ delayed()->nop();
-
- // Pending exception after the safepoint
-
- __ bind(pending);
-
- RegisterSaver::restore_live_registers(masm);
-
- // We are back the the original state on entry.
-
- // Tail-call forward_exception_entry, with the issuing PC in O7,
- // so it looks like the original nmethod called forward_exception_entry.
- __ set((intptr_t)StubRoutines::forward_exception_entry(), O0);
- __ JMP(O0, 0);
- __ delayed()->nop();
-
- // -------------
- // make sure all code is generated
- masm->flush();
-
- // return exception blob
- return SafepointBlob::create(&buffer, oop_maps, frame_size_words);
-}
-
-//
-// generate_resolve_blob - call resolution (static/virtual/opt-virtual/ic-miss
-//
-// Generate a stub that calls into vm to find out the proper destination
-// of a java call. All the argument registers are live at this point
-// but since this is generic code we don't know what they are and the caller
-// must do any gc of the args.
-//
-RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
- assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before");
-
- // allocate space for the code
- ResourceMark rm;
- // setup code generation tools
- // Measured 8/7/03 at 896 in 32bit debug build (no VerifyThread)
- // Measured 8/7/03 at 1080 in 32bit debug build (VerifyThread)
- CodeBuffer buffer(name, 1600, 512);
- MacroAssembler* masm = new MacroAssembler(&buffer);
- int frame_size_words;
- OopMapSet *oop_maps = new OopMapSet();
- OopMap* map = NULL;
-
- int start = __ offset();
-
- map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
-
- int frame_complete = __ offset();
-
- // setup last_Java_sp (blows G4)
- __ set_last_Java_frame(SP, noreg);
-
- // call into the runtime to handle illegal instructions exception
- // Do not use call_VM_leaf, because we need to make a GC map at this call site.
- __ mov(G2_thread, O0);
- __ save_thread(L7_thread_cache);
- __ call(destination, relocInfo::runtime_call_type);
- __ delayed()->nop();
-
- // O0 contains the address we are going to jump to assuming no exception got installed
-
- // Set an oopmap for the call site.
- // We need this not only for callee-saved registers, but also for volatile
- // registers that the compiler might be keeping live across a safepoint.
-
- oop_maps->add_gc_map( __ offset() - start, map);
-
- __ restore_thread(L7_thread_cache);
- // clear last_Java_sp
- __ reset_last_Java_frame();
-
- // Check for exceptions
- Label pending;
-
- __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O1);
- __ br_notnull_short(O1, Assembler::pn, pending);
-
- // get the returned Method*
-
- __ get_vm_result_2(G5_method);
- __ stx(G5_method, SP, RegisterSaver::G5_offset()+STACK_BIAS);
-
- // O0 is where we want to jump, overwrite G3 which is saved and scratch
-
- __ stx(O0, SP, RegisterSaver::G3_offset()+STACK_BIAS);
-
- RegisterSaver::restore_live_registers(masm);
-
- // We are back the the original state on entry and ready to go.
-
- __ JMP(G3, 0);
- __ delayed()->nop();
-
- // Pending exception after the safepoint
-
- __ bind(pending);
-
- RegisterSaver::restore_live_registers(masm);
-
- // We are back the the original state on entry.
-
- // Tail-call forward_exception_entry, with the issuing PC in O7,
- // so it looks like the original nmethod called forward_exception_entry.
- __ set((intptr_t)StubRoutines::forward_exception_entry(), O0);
- __ JMP(O0, 0);
- __ delayed()->nop();
-
- // -------------
- // make sure all code is generated
- masm->flush();
-
- // return the blob
- // frame_size_words or bytes??
- return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
-}
diff --git a/src/hotspot/cpu/sparc/sparc.ad b/src/hotspot/cpu/sparc/sparc.ad
deleted file mode 100644
index abb3d04b47f..00000000000
--- a/src/hotspot/cpu/sparc/sparc.ad
+++ /dev/null
@@ -1,10950 +0,0 @@
-//
-// Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
-// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-//
-// This code is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License version 2 only, as
-// published by the Free Software Foundation.
-//
-// This code is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// version 2 for more details (a copy is included in the LICENSE file that
-// accompanied this code).
-//
-// You should have received a copy of the GNU General Public License version
-// 2 along with this work; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-//
-// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-// or visit www.oracle.com if you need additional information or have any
-// questions.
-//
-//
-
-// SPARC Architecture Description File
-
-//----------REGISTER DEFINITION BLOCK------------------------------------------
-// This information is used by the matcher and the register allocator to
-// describe individual registers and classes of registers within the target
-// archtecture.
-register %{
-//----------Architecture Description Register Definitions----------------------
-// General Registers
-// "reg_def" name ( register save type, C convention save type,
-// ideal register type, encoding, vm name );
-// Register Save Types:
-//
-// NS = No-Save: The register allocator assumes that these registers
-// can be used without saving upon entry to the method, &
-// that they do not need to be saved at call sites.
-//
-// SOC = Save-On-Call: The register allocator assumes that these registers
-// can be used without saving upon entry to the method,
-// but that they must be saved at call sites.
-//
-// SOE = Save-On-Entry: The register allocator assumes that these registers
-// must be saved before using them upon entry to the
-// method, but they do not need to be saved at call
-// sites.
-//
-// AS = Always-Save: The register allocator assumes that these registers
-// must be saved before using them upon entry to the
-// method, & that they must be saved at call sites.
-//
-// Ideal Register Type is used to determine how to save & restore a
-// register. Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get
-// spilled with LoadP/StoreP. If the register supports both, use Op_RegI.
-//
-// The encoding number is the actual bit-pattern placed into the opcodes.
-
-
-// ----------------------------
-// Integer/Long Registers
-// ----------------------------
-
-// Need to expose the hi/lo aspect of 64-bit registers
-// This register set is used for both the 64-bit build and
-// the 32-bit build with 1-register longs.
-
-// Global Registers 0-7
-reg_def R_G0H( NS, NS, Op_RegI,128, G0->as_VMReg()->next());
-reg_def R_G0 ( NS, NS, Op_RegI, 0, G0->as_VMReg());
-reg_def R_G1H(SOC, SOC, Op_RegI,129, G1->as_VMReg()->next());
-reg_def R_G1 (SOC, SOC, Op_RegI, 1, G1->as_VMReg());
-reg_def R_G2H( NS, NS, Op_RegI,130, G2->as_VMReg()->next());
-reg_def R_G2 ( NS, NS, Op_RegI, 2, G2->as_VMReg());
-reg_def R_G3H(SOC, SOC, Op_RegI,131, G3->as_VMReg()->next());
-reg_def R_G3 (SOC, SOC, Op_RegI, 3, G3->as_VMReg());
-reg_def R_G4H(SOC, SOC, Op_RegI,132, G4->as_VMReg()->next());
-reg_def R_G4 (SOC, SOC, Op_RegI, 4, G4->as_VMReg());
-reg_def R_G5H(SOC, SOC, Op_RegI,133, G5->as_VMReg()->next());
-reg_def R_G5 (SOC, SOC, Op_RegI, 5, G5->as_VMReg());
-reg_def R_G6H( NS, NS, Op_RegI,134, G6->as_VMReg()->next());
-reg_def R_G6 ( NS, NS, Op_RegI, 6, G6->as_VMReg());
-reg_def R_G7H( NS, NS, Op_RegI,135, G7->as_VMReg()->next());
-reg_def R_G7 ( NS, NS, Op_RegI, 7, G7->as_VMReg());
-
-// Output Registers 0-7
-reg_def R_O0H(SOC, SOC, Op_RegI,136, O0->as_VMReg()->next());
-reg_def R_O0 (SOC, SOC, Op_RegI, 8, O0->as_VMReg());
-reg_def R_O1H(SOC, SOC, Op_RegI,137, O1->as_VMReg()->next());
-reg_def R_O1 (SOC, SOC, Op_RegI, 9, O1->as_VMReg());
-reg_def R_O2H(SOC, SOC, Op_RegI,138, O2->as_VMReg()->next());
-reg_def R_O2 (SOC, SOC, Op_RegI, 10, O2->as_VMReg());
-reg_def R_O3H(SOC, SOC, Op_RegI,139, O3->as_VMReg()->next());
-reg_def R_O3 (SOC, SOC, Op_RegI, 11, O3->as_VMReg());
-reg_def R_O4H(SOC, SOC, Op_RegI,140, O4->as_VMReg()->next());
-reg_def R_O4 (SOC, SOC, Op_RegI, 12, O4->as_VMReg());
-reg_def R_O5H(SOC, SOC, Op_RegI,141, O5->as_VMReg()->next());
-reg_def R_O5 (SOC, SOC, Op_RegI, 13, O5->as_VMReg());
-reg_def R_SPH( NS, NS, Op_RegI,142, SP->as_VMReg()->next());
-reg_def R_SP ( NS, NS, Op_RegI, 14, SP->as_VMReg());
-reg_def R_O7H(SOC, SOC, Op_RegI,143, O7->as_VMReg()->next());
-reg_def R_O7 (SOC, SOC, Op_RegI, 15, O7->as_VMReg());
-
-// Local Registers 0-7
-reg_def R_L0H( NS, NS, Op_RegI,144, L0->as_VMReg()->next());
-reg_def R_L0 ( NS, NS, Op_RegI, 16, L0->as_VMReg());
-reg_def R_L1H( NS, NS, Op_RegI,145, L1->as_VMReg()->next());
-reg_def R_L1 ( NS, NS, Op_RegI, 17, L1->as_VMReg());
-reg_def R_L2H( NS, NS, Op_RegI,146, L2->as_VMReg()->next());
-reg_def R_L2 ( NS, NS, Op_RegI, 18, L2->as_VMReg());
-reg_def R_L3H( NS, NS, Op_RegI,147, L3->as_VMReg()->next());
-reg_def R_L3 ( NS, NS, Op_RegI, 19, L3->as_VMReg());
-reg_def R_L4H( NS, NS, Op_RegI,148, L4->as_VMReg()->next());
-reg_def R_L4 ( NS, NS, Op_RegI, 20, L4->as_VMReg());
-reg_def R_L5H( NS, NS, Op_RegI,149, L5->as_VMReg()->next());
-reg_def R_L5 ( NS, NS, Op_RegI, 21, L5->as_VMReg());
-reg_def R_L6H( NS, NS, Op_RegI,150, L6->as_VMReg()->next());
-reg_def R_L6 ( NS, NS, Op_RegI, 22, L6->as_VMReg());
-reg_def R_L7H( NS, NS, Op_RegI,151, L7->as_VMReg()->next());
-reg_def R_L7 ( NS, NS, Op_RegI, 23, L7->as_VMReg());
-
-// Input Registers 0-7
-reg_def R_I0H( NS, NS, Op_RegI,152, I0->as_VMReg()->next());
-reg_def R_I0 ( NS, NS, Op_RegI, 24, I0->as_VMReg());
-reg_def R_I1H( NS, NS, Op_RegI,153, I1->as_VMReg()->next());
-reg_def R_I1 ( NS, NS, Op_RegI, 25, I1->as_VMReg());
-reg_def R_I2H( NS, NS, Op_RegI,154, I2->as_VMReg()->next());
-reg_def R_I2 ( NS, NS, Op_RegI, 26, I2->as_VMReg());
-reg_def R_I3H( NS, NS, Op_RegI,155, I3->as_VMReg()->next());
-reg_def R_I3 ( NS, NS, Op_RegI, 27, I3->as_VMReg());
-reg_def R_I4H( NS, NS, Op_RegI,156, I4->as_VMReg()->next());
-reg_def R_I4 ( NS, NS, Op_RegI, 28, I4->as_VMReg());
-reg_def R_I5H( NS, NS, Op_RegI,157, I5->as_VMReg()->next());
-reg_def R_I5 ( NS, NS, Op_RegI, 29, I5->as_VMReg());
-reg_def R_FPH( NS, NS, Op_RegI,158, FP->as_VMReg()->next());
-reg_def R_FP ( NS, NS, Op_RegI, 30, FP->as_VMReg());
-reg_def R_I7H( NS, NS, Op_RegI,159, I7->as_VMReg()->next());
-reg_def R_I7 ( NS, NS, Op_RegI, 31, I7->as_VMReg());
-
-// ----------------------------
-// Float/Double Registers
-// ----------------------------
-
-// Float Registers
-reg_def R_F0 ( SOC, SOC, Op_RegF, 0, F0->as_VMReg());
-reg_def R_F1 ( SOC, SOC, Op_RegF, 1, F1->as_VMReg());
-reg_def R_F2 ( SOC, SOC, Op_RegF, 2, F2->as_VMReg());
-reg_def R_F3 ( SOC, SOC, Op_RegF, 3, F3->as_VMReg());
-reg_def R_F4 ( SOC, SOC, Op_RegF, 4, F4->as_VMReg());
-reg_def R_F5 ( SOC, SOC, Op_RegF, 5, F5->as_VMReg());
-reg_def R_F6 ( SOC, SOC, Op_RegF, 6, F6->as_VMReg());
-reg_def R_F7 ( SOC, SOC, Op_RegF, 7, F7->as_VMReg());
-reg_def R_F8 ( SOC, SOC, Op_RegF, 8, F8->as_VMReg());
-reg_def R_F9 ( SOC, SOC, Op_RegF, 9, F9->as_VMReg());
-reg_def R_F10( SOC, SOC, Op_RegF, 10, F10->as_VMReg());
-reg_def R_F11( SOC, SOC, Op_RegF, 11, F11->as_VMReg());
-reg_def R_F12( SOC, SOC, Op_RegF, 12, F12->as_VMReg());
-reg_def R_F13( SOC, SOC, Op_RegF, 13, F13->as_VMReg());
-reg_def R_F14( SOC, SOC, Op_RegF, 14, F14->as_VMReg());
-reg_def R_F15( SOC, SOC, Op_RegF, 15, F15->as_VMReg());
-reg_def R_F16( SOC, SOC, Op_RegF, 16, F16->as_VMReg());
-reg_def R_F17( SOC, SOC, Op_RegF, 17, F17->as_VMReg());
-reg_def R_F18( SOC, SOC, Op_RegF, 18, F18->as_VMReg());
-reg_def R_F19( SOC, SOC, Op_RegF, 19, F19->as_VMReg());
-reg_def R_F20( SOC, SOC, Op_RegF, 20, F20->as_VMReg());
-reg_def R_F21( SOC, SOC, Op_RegF, 21, F21->as_VMReg());
-reg_def R_F22( SOC, SOC, Op_RegF, 22, F22->as_VMReg());
-reg_def R_F23( SOC, SOC, Op_RegF, 23, F23->as_VMReg());
-reg_def R_F24( SOC, SOC, Op_RegF, 24, F24->as_VMReg());
-reg_def R_F25( SOC, SOC, Op_RegF, 25, F25->as_VMReg());
-reg_def R_F26( SOC, SOC, Op_RegF, 26, F26->as_VMReg());
-reg_def R_F27( SOC, SOC, Op_RegF, 27, F27->as_VMReg());
-reg_def R_F28( SOC, SOC, Op_RegF, 28, F28->as_VMReg());
-reg_def R_F29( SOC, SOC, Op_RegF, 29, F29->as_VMReg());
-reg_def R_F30( SOC, SOC, Op_RegF, 30, F30->as_VMReg());
-reg_def R_F31( SOC, SOC, Op_RegF, 31, F31->as_VMReg());
-
-// Double Registers
-// The rules of ADL require that double registers be defined in pairs.
-// Each pair must be two 32-bit values, but not necessarily a pair of
-// single float registers. In each pair, ADLC-assigned register numbers
-// must be adjacent, with the lower number even. Finally, when the
-// CPU stores such a register pair to memory, the word associated with
-// the lower ADLC-assigned number must be stored to the lower address.
-
-// These definitions specify the actual bit encodings of the sparc
-// double fp register numbers. FloatRegisterImpl in register_sparc.hpp
-// wants 0-63, so we have to convert every time we want to use fp regs
-// with the macroassembler, using reg_to_DoubleFloatRegister_object().
-// 255 is a flag meaning "don't go here".
-// I believe we can't handle callee-save doubles D32 and up until
-// the place in the sparc stack crawler that asserts on the 255 is
-// fixed up.
-reg_def R_D32 (SOC, SOC, Op_RegD, 1, F32->as_VMReg());
-reg_def R_D32x(SOC, SOC, Op_RegD,255, F32->as_VMReg()->next());
-reg_def R_D34 (SOC, SOC, Op_RegD, 3, F34->as_VMReg());
-reg_def R_D34x(SOC, SOC, Op_RegD,255, F34->as_VMReg()->next());
-reg_def R_D36 (SOC, SOC, Op_RegD, 5, F36->as_VMReg());
-reg_def R_D36x(SOC, SOC, Op_RegD,255, F36->as_VMReg()->next());
-reg_def R_D38 (SOC, SOC, Op_RegD, 7, F38->as_VMReg());
-reg_def R_D38x(SOC, SOC, Op_RegD,255, F38->as_VMReg()->next());
-reg_def R_D40 (SOC, SOC, Op_RegD, 9, F40->as_VMReg());
-reg_def R_D40x(SOC, SOC, Op_RegD,255, F40->as_VMReg()->next());
-reg_def R_D42 (SOC, SOC, Op_RegD, 11, F42->as_VMReg());
-reg_def R_D42x(SOC, SOC, Op_RegD,255, F42->as_VMReg()->next());
-reg_def R_D44 (SOC, SOC, Op_RegD, 13, F44->as_VMReg());
-reg_def R_D44x(SOC, SOC, Op_RegD,255, F44->as_VMReg()->next());
-reg_def R_D46 (SOC, SOC, Op_RegD, 15, F46->as_VMReg());
-reg_def R_D46x(SOC, SOC, Op_RegD,255, F46->as_VMReg()->next());
-reg_def R_D48 (SOC, SOC, Op_RegD, 17, F48->as_VMReg());
-reg_def R_D48x(SOC, SOC, Op_RegD,255, F48->as_VMReg()->next());
-reg_def R_D50 (SOC, SOC, Op_RegD, 19, F50->as_VMReg());
-reg_def R_D50x(SOC, SOC, Op_RegD,255, F50->as_VMReg()->next());
-reg_def R_D52 (SOC, SOC, Op_RegD, 21, F52->as_VMReg());
-reg_def R_D52x(SOC, SOC, Op_RegD,255, F52->as_VMReg()->next());
-reg_def R_D54 (SOC, SOC, Op_RegD, 23, F54->as_VMReg());
-reg_def R_D54x(SOC, SOC, Op_RegD,255, F54->as_VMReg()->next());
-reg_def R_D56 (SOC, SOC, Op_RegD, 25, F56->as_VMReg());
-reg_def R_D56x(SOC, SOC, Op_RegD,255, F56->as_VMReg()->next());
-reg_def R_D58 (SOC, SOC, Op_RegD, 27, F58->as_VMReg());
-reg_def R_D58x(SOC, SOC, Op_RegD,255, F58->as_VMReg()->next());
-reg_def R_D60 (SOC, SOC, Op_RegD, 29, F60->as_VMReg());
-reg_def R_D60x(SOC, SOC, Op_RegD,255, F60->as_VMReg()->next());
-reg_def R_D62 (SOC, SOC, Op_RegD, 31, F62->as_VMReg());
-reg_def R_D62x(SOC, SOC, Op_RegD,255, F62->as_VMReg()->next());
-
-
-// ----------------------------
-// Special Registers
-// Condition Codes Flag Registers
-// I tried to break out ICC and XCC but it's not very pretty.
-// Every Sparc instruction which defs/kills one also kills the other.
-// Hence every compare instruction which defs one kind of flags ends
-// up needing a kill of the other.
-reg_def CCR (SOC, SOC, Op_RegFlags, 0, VMRegImpl::Bad());
-
-reg_def FCC0(SOC, SOC, Op_RegFlags, 0, VMRegImpl::Bad());
-reg_def FCC1(SOC, SOC, Op_RegFlags, 1, VMRegImpl::Bad());
-reg_def FCC2(SOC, SOC, Op_RegFlags, 2, VMRegImpl::Bad());
-reg_def FCC3(SOC, SOC, Op_RegFlags, 3, VMRegImpl::Bad());
-
-// ----------------------------
-// Specify the enum values for the registers. These enums are only used by the
-// OptoReg "class". We can convert these enum values at will to VMReg when needed
-// for visibility to the rest of the vm. The order of this enum influences the
-// register allocator so having the freedom to set this order and not be stuck
-// with the order that is natural for the rest of the vm is worth it.
-alloc_class chunk0(
- R_L0,R_L0H, R_L1,R_L1H, R_L2,R_L2H, R_L3,R_L3H, R_L4,R_L4H, R_L5,R_L5H, R_L6,R_L6H, R_L7,R_L7H,
- R_G0,R_G0H, R_G1,R_G1H, R_G2,R_G2H, R_G3,R_G3H, R_G4,R_G4H, R_G5,R_G5H, R_G6,R_G6H, R_G7,R_G7H,
- R_O7,R_O7H, R_SP,R_SPH, R_O0,R_O0H, R_O1,R_O1H, R_O2,R_O2H, R_O3,R_O3H, R_O4,R_O4H, R_O5,R_O5H,
- R_I0,R_I0H, R_I1,R_I1H, R_I2,R_I2H, R_I3,R_I3H, R_I4,R_I4H, R_I5,R_I5H, R_FP,R_FPH, R_I7,R_I7H);
-
-// Note that a register is not allocatable unless it is also mentioned
-// in a widely-used reg_class below. Thus, R_G7 and R_G0 are outside i_reg.
-
-alloc_class chunk1(
- // The first registers listed here are those most likely to be used
- // as temporaries. We move F0..F7 away from the front of the list,
- // to reduce the likelihood of interferences with parameters and
- // return values. Likewise, we avoid using F0/F1 for parameters,
- // since they are used for return values.
- // This FPU fine-tuning is worth about 1% on the SPEC geomean.
- R_F8 ,R_F9 ,R_F10,R_F11,R_F12,R_F13,R_F14,R_F15,
- R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,
- R_F24,R_F25,R_F26,R_F27,R_F28,R_F29,R_F30,R_F31,
- R_F0 ,R_F1 ,R_F2 ,R_F3 ,R_F4 ,R_F5 ,R_F6 ,R_F7 , // used for arguments and return values
- R_D32,R_D32x,R_D34,R_D34x,R_D36,R_D36x,R_D38,R_D38x,
- R_D40,R_D40x,R_D42,R_D42x,R_D44,R_D44x,R_D46,R_D46x,
- R_D48,R_D48x,R_D50,R_D50x,R_D52,R_D52x,R_D54,R_D54x,
- R_D56,R_D56x,R_D58,R_D58x,R_D60,R_D60x,R_D62,R_D62x);
-
-alloc_class chunk2(CCR, FCC0, FCC1, FCC2, FCC3);
-
-//----------Architecture Description Register Classes--------------------------
-// Several register classes are automatically defined based upon information in
-// this architecture description.
-// 1) reg_class inline_cache_reg ( as defined in frame section )
-// 2) reg_class interpreter_method_oop_reg ( as defined in frame section )
-// 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ )
-//
-
-// G0 is not included in integer class since it has special meaning.
-reg_class g0_reg(R_G0);
-
-// ----------------------------
-// Integer Register Classes
-// ----------------------------
-// Exclusions from i_reg:
-// R_G0: hardwired zero
-// R_G2: reserved by HotSpot to the TLS register (invariant within Java)
-// R_G6: reserved by Solaris ABI to tools
-// R_G7: reserved by Solaris ABI to libthread
-// R_O7: Used as a temp in many encodings
-reg_class int_reg(R_G1,R_G3,R_G4,R_G5,R_O0,R_O1,R_O2,R_O3,R_O4,R_O5,R_L0,R_L1,R_L2,R_L3,R_L4,R_L5,R_L6,R_L7,R_I0,R_I1,R_I2,R_I3,R_I4,R_I5);
-
-// Class for all integer registers, except the G registers. This is used for
-// encodings which use G registers as temps. The regular inputs to such
-// instructions use a "notemp_" prefix, as a hack to ensure that the allocator
-// will not put an input into a temp register.
-reg_class notemp_int_reg(R_O0,R_O1,R_O2,R_O3,R_O4,R_O5,R_L0,R_L1,R_L2,R_L3,R_L4,R_L5,R_L6,R_L7,R_I0,R_I1,R_I2,R_I3,R_I4,R_I5);
-
-reg_class g1_regI(R_G1);
-reg_class g3_regI(R_G3);
-reg_class g4_regI(R_G4);
-reg_class o0_regI(R_O0);
-reg_class o7_regI(R_O7);
-
-// ----------------------------
-// Pointer Register Classes
-// ----------------------------
-// 64-bit build means 64-bit pointers means hi/lo pairs
-reg_class ptr_reg( R_G1H,R_G1, R_G3H,R_G3, R_G4H,R_G4, R_G5H,R_G5,
- R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5,
- R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7,
- R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5 );
-// Lock encodings use G3 and G4 internally
-reg_class lock_ptr_reg( R_G1H,R_G1, R_G5H,R_G5,
- R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5,
- R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7,
- R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5 );
-// Special class for storeP instructions, which can store SP or RPC to TLS.
-// It is also used for memory addressing, allowing direct TLS addressing.
-reg_class sp_ptr_reg( R_G1H,R_G1, R_G2H,R_G2, R_G3H,R_G3, R_G4H,R_G4, R_G5H,R_G5,
- R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5, R_SPH,R_SP,
- R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7,
- R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5, R_FPH,R_FP );
-// R_L7 is the lowest-priority callee-save (i.e., NS) register
-// We use it to save R_G2 across calls out of Java.
-reg_class l7_regP(R_L7H,R_L7);
-
-// Other special pointer regs
-reg_class g1_regP(R_G1H,R_G1);
-reg_class g2_regP(R_G2H,R_G2);
-reg_class g3_regP(R_G3H,R_G3);
-reg_class g4_regP(R_G4H,R_G4);
-reg_class g5_regP(R_G5H,R_G5);
-reg_class i0_regP(R_I0H,R_I0);
-reg_class o0_regP(R_O0H,R_O0);
-reg_class o1_regP(R_O1H,R_O1);
-reg_class o2_regP(R_O2H,R_O2);
-reg_class o7_regP(R_O7H,R_O7);
-
-
-// ----------------------------
-// Long Register Classes
-// ----------------------------
-// Longs in 1 register. Aligned adjacent hi/lo pairs.
-// Note: O7 is never in this class; it is sometimes used as an encoding temp.
-reg_class long_reg( R_G1H,R_G1, R_G3H,R_G3, R_G4H,R_G4, R_G5H,R_G5
- ,R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5
-// 64-bit, longs in 1 register: use all 64-bit integer registers
- ,R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7
- ,R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5
- );
-
-reg_class g1_regL(R_G1H,R_G1);
-reg_class g3_regL(R_G3H,R_G3);
-reg_class o2_regL(R_O2H,R_O2);
-reg_class o7_regL(R_O7H,R_O7);
-
-// ----------------------------
-// Special Class for Condition Code Flags Register
-reg_class int_flags(CCR);
-reg_class float_flags(FCC0,FCC1,FCC2,FCC3);
-reg_class float_flag0(FCC0);
-
-
-// ----------------------------
-// Float Point Register Classes
-// ----------------------------
-// Skip F30/F31, they are reserved for mem-mem copies
-reg_class sflt_reg(R_F0,R_F1,R_F2,R_F3,R_F4,R_F5,R_F6,R_F7,R_F8,R_F9,R_F10,R_F11,R_F12,R_F13,R_F14,R_F15,R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29);
-
-// Paired floating point registers--they show up in the same order as the floats,
-// but they are used with the "Op_RegD" type, and always occur in even/odd pairs.
-reg_class dflt_reg(R_F0, R_F1, R_F2, R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10,R_F11,R_F12,R_F13,R_F14,R_F15,
- R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29,
- /* Use extra V9 double registers; this AD file does not support V8 */
- R_D32,R_D32x,R_D34,R_D34x,R_D36,R_D36x,R_D38,R_D38x,R_D40,R_D40x,R_D42,R_D42x,R_D44,R_D44x,R_D46,R_D46x,
- R_D48,R_D48x,R_D50,R_D50x,R_D52,R_D52x,R_D54,R_D54x,R_D56,R_D56x,R_D58,R_D58x,R_D60,R_D60x,R_D62,R_D62x
- );
-
-// Paired floating point registers--they show up in the same order as the floats,
-// but they are used with the "Op_RegD" type, and always occur in even/odd pairs.
-// This class is usable for mis-aligned loads as happen in I2C adapters.
-reg_class dflt_low_reg(R_F0, R_F1, R_F2, R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10,R_F11,R_F12,R_F13,R_F14,R_F15,
- R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29);
-%}
-
-//----------DEFINITION BLOCK---------------------------------------------------
-// Define name --> value mappings to inform the ADLC of an integer valued name
-// Current support includes integer values in the range [0, 0x7FFFFFFF]
-// Format:
-// int_def ( , );
-// Generated Code in ad_.hpp
-// #define ()
-// // value ==
-// Generated code in ad_.cpp adlc_verification()
-// assert( == , "Expect () to equal ");
-//
-definitions %{
-// The default cost (of an ALU instruction).
- int_def DEFAULT_COST ( 100, 100);
- int_def HUGE_COST (1000000, 1000000);
-
-// Memory refs are twice as expensive as run-of-the-mill.
- int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2);
-
-// Branches are even more expensive.
- int_def BRANCH_COST ( 300, DEFAULT_COST * 3);
- int_def CALL_COST ( 300, DEFAULT_COST * 3);
-%}
-
-
-//----------SOURCE BLOCK-------------------------------------------------------
-// This is a block of C++ code which provides values, functions, and
-// definitions necessary in the rest of the architecture description
-source_hpp %{
-// Header information of the source block.
-// Method declarations/definitions which are used outside
-// the ad-scope can conveniently be defined here.
-//
-// To keep related declarations/definitions/uses close together,
-// we switch between source %{ }% and source_hpp %{ }% freely as needed.
-
-// Must be visible to the DFA in dfa_sparc.cpp
-extern bool can_branch_register( Node *bol, Node *cmp );
-
-extern bool use_block_zeroing(Node* count);
-
-// Macros to extract hi & lo halves from a long pair.
-// G0 is not part of any long pair, so assert on that.
-// Prevents accidentally using G1 instead of G0.
-#define LONG_HI_REG(x) (x)
-#define LONG_LO_REG(x) (x)
-
-class CallStubImpl {
-
- //--------------------------------------------------------------
- //---< Used for optimization in Compile::Shorten_branches >---
- //--------------------------------------------------------------
-
- public:
- // Size of call trampoline stub.
- static uint size_call_trampoline() {
- return 0; // no call trampolines on this platform
- }
-
- // number of relocations needed by a call trampoline stub
- static uint reloc_call_trampoline() {
- return 0; // no call trampolines on this platform
- }
-};
-
-class HandlerImpl {
-
- public:
-
- static int emit_exception_handler(CodeBuffer &cbuf);
- static int emit_deopt_handler(CodeBuffer& cbuf);
-
- static uint size_exception_handler() {
- return ( NativeJump::instruction_size ); // sethi;jmp;nop
- }
-
- static uint size_deopt_handler() {
- return ( 4+ NativeJump::instruction_size ); // save;sethi;jmp;restore
- }
-};
-
-class Node::PD {
-public:
- enum NodeFlags {
- _last_flag = Node::_last_flag
- };
-};
-
-%}
-
-source %{
-#define __ _masm.
-
-// tertiary op of a LoadP or StoreP encoding
-#define REGP_OP true
-
-static FloatRegister reg_to_SingleFloatRegister_object(int register_encoding);
-static FloatRegister reg_to_DoubleFloatRegister_object(int register_encoding);
-static Register reg_to_register_object(int register_encoding);
-
-void PhaseOutput::pd_perform_mach_node_analysis() {
-}
-
-int MachNode::pd_alignment_required() const {
- return 1;
-}
-
-int MachNode::compute_padding(int current_offset) const {
- return 0;
-}
-
-// Used by the DFA in dfa_sparc.cpp.
-// Check for being able to use a V9 branch-on-register. Requires a
-// compare-vs-zero, equal/not-equal, of a value which was zero- or sign-
-// extended. Doesn't work following an integer ADD, for example, because of
-// overflow (-1 incremented yields 0 plus a carry in the high-order word). On
-// 32-bit V9 systems, interrupts currently blow away the high-order 32 bits and
-// replace them with zero, which could become sign-extension in a different OS
-// release. There's no obvious reason why an interrupt will ever fill these
-// bits with non-zero junk (the registers are reloaded with standard LD
-// instructions which either zero-fill or sign-fill).
-bool can_branch_register( Node *bol, Node *cmp ) {
- if( !BranchOnRegister ) return false;
- if( cmp->Opcode() == Op_CmpP )
- return true; // No problems with pointer compares
- if( cmp->Opcode() == Op_CmpL )
- return true; // No problems with long compares
-
- if( !SparcV9RegsHiBitsZero ) return false;
- if( bol->as_Bool()->_test._test != BoolTest::ne &&
- bol->as_Bool()->_test._test != BoolTest::eq )
- return false;
-
- // Check for comparing against a 'safe' value. Any operation which
- // clears out the high word is safe. Thus, loads and certain shifts
- // are safe, as are non-negative constants. Any operation which
- // preserves zero bits in the high word is safe as long as each of its
- // inputs are safe. Thus, phis and bitwise booleans are safe if their
- // inputs are safe. At present, the only important case to recognize
- // seems to be loads. Constants should fold away, and shifts &
- // logicals can use the 'cc' forms.
- Node *x = cmp->in(1);
- if( x->is_Load() ) return true;
- if( x->is_Phi() ) {
- for( uint i = 1; i < x->req(); i++ )
- if( !x->in(i)->is_Load() )
- return false;
- return true;
- }
- return false;
-}
-
-bool use_block_zeroing(Node* count) {
- // Use BIS for zeroing if count is not constant
- // or it is >= BlockZeroingLowLimit.
- return UseBlockZeroing && (count->find_intptr_t_con(BlockZeroingLowLimit) >= BlockZeroingLowLimit);
-}
-
-// ****************************************************************************
-
-// REQUIRED FUNCTIONALITY
-
-// !!!!! Special hack to get all type of calls to specify the byte offset
-// from the start of the call to the point where the return address
-// will point.
-// The "return address" is the address of the call instruction, plus 8.
-
-int MachCallStaticJavaNode::ret_addr_offset() {
- int offset = NativeCall::instruction_size; // call; delay slot
- if (_method_handle_invoke)
- offset += 4; // restore SP
- return offset;
-}
-
-int MachCallDynamicJavaNode::ret_addr_offset() {
- int vtable_index = this->_vtable_index;
- if (vtable_index < 0) {
- // must be invalid_vtable_index, not nonvirtual_vtable_index
- assert(vtable_index == Method::invalid_vtable_index, "correct sentinel value");
- return (NativeMovConstReg::instruction_size +
- NativeCall::instruction_size); // sethi; setlo; call; delay slot
- } else {
- assert(!UseInlineCaches, "expect vtable calls only if not using ICs");
- int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes();
- int v_off = entry_offset + vtableEntry::method_offset_in_bytes();
- int klass_load_size;
- if (UseCompressedClassPointers) {
- assert(Universe::heap() != NULL, "java heap should be initialized");
- klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord;
- } else {
- klass_load_size = 1*BytesPerInstWord;
- }
- if (Assembler::is_simm13(v_off)) {
- return klass_load_size +
- (2*BytesPerInstWord + // ld_ptr, ld_ptr
- NativeCall::instruction_size); // call; delay slot
- } else {
- return klass_load_size +
- (4*BytesPerInstWord + // set_hi, set, ld_ptr, ld_ptr
- NativeCall::instruction_size); // call; delay slot
- }
- }
-}
-
-int MachCallRuntimeNode::ret_addr_offset() {
- if (MacroAssembler::is_far_target(entry_point())) {
- return NativeFarCall::instruction_size;
- } else {
- return NativeCall::instruction_size;
- }
-}
-
-// Indicate if the safepoint node needs the polling page as an input.
-// Since Sparc does not have absolute addressing, it does.
-bool SafePointNode::needs_polling_address_input() {
- return true;
-}
-
-// emit an interrupt that is caught by the debugger (for debugging compiler)
-void emit_break(CodeBuffer &cbuf) {
- C2_MacroAssembler _masm(&cbuf);
- __ breakpoint_trap();
-}
-
-#ifndef PRODUCT
-void MachBreakpointNode::format( PhaseRegAlloc *, outputStream *st ) const {
- st->print("TA");
-}
-#endif
-
-void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
- emit_break(cbuf);
-}
-
-uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
- return MachNode::size(ra_);
-}
-
-// Traceable jump
-void emit_jmpl(CodeBuffer &cbuf, int jump_target) {
- C2_MacroAssembler _masm(&cbuf);
- Register rdest = reg_to_register_object(jump_target);
- __ JMP(rdest, 0);
- __ delayed()->nop();
-}
-
-// Traceable jump and set exception pc
-void emit_jmpl_set_exception_pc(CodeBuffer &cbuf, int jump_target) {
- C2_MacroAssembler _masm(&cbuf);
- Register rdest = reg_to_register_object(jump_target);
- __ JMP(rdest, 0);
- __ delayed()->add(O7, frame::pc_return_offset, Oissuing_pc );
-}
-
-void emit_nop(CodeBuffer &cbuf) {
- C2_MacroAssembler _masm(&cbuf);
- __ nop();
-}
-
-void emit_illtrap(CodeBuffer &cbuf) {
- C2_MacroAssembler _masm(&cbuf);
- __ illtrap(0);
-}
-
-
-intptr_t get_offset_from_base(const MachNode* n, const TypePtr* atype, int disp32) {
- assert(n->rule() != loadUB_rule, "");
-
- intptr_t offset = 0;
- const TypePtr *adr_type = TYPE_PTR_SENTINAL; // Check for base==RegI, disp==immP
- const Node* addr = n->get_base_and_disp(offset, adr_type);
- assert(adr_type == (const TypePtr*)-1, "VerifyOops: no support for sparc operands with base==RegI, disp==immP");
- assert(addr != NULL && addr != (Node*)-1, "invalid addr");
- assert(addr->bottom_type()->isa_oopptr() == atype, "");
- atype = atype->add_offset(offset);
- assert(disp32 == offset, "wrong disp32");
- return atype->_offset;
-}
-
-
-intptr_t get_offset_from_base_2(const MachNode* n, const TypePtr* atype, int disp32) {
- assert(n->rule() != loadUB_rule, "");
-
- intptr_t offset = 0;
- Node* addr = n->in(2);
- assert(addr->bottom_type()->isa_oopptr() == atype, "");
- if (addr->is_Mach() && addr->as_Mach()->ideal_Opcode() == Op_AddP) {
- Node* a = addr->in(2/*AddPNode::Address*/);
- Node* o = addr->in(3/*AddPNode::Offset*/);
- offset = o->is_Con() ? o->bottom_type()->is_intptr_t()->get_con() : Type::OffsetBot;
- atype = a->bottom_type()->is_ptr()->add_offset(offset);
- assert(atype->isa_oop_ptr(), "still an oop");
- }
- offset = atype->is_ptr()->_offset;
- if (offset != Type::OffsetBot) offset += disp32;
- return offset;
-}
-
-static inline jlong replicate_immI(int con, int count, int width) {
- // Load a constant replicated "count" times with width "width"
- assert(count*width == 8 && width <= 4, "sanity");
- int bit_width = width * 8;
- jlong val = con;
- val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits
- for (int i = 0; i < count - 1; i++) {
- val |= (val << bit_width);
- }
- return val;
-}
-
-static inline jlong replicate_immF(float con) {
- // Replicate float con 2 times and pack into vector.
- int val = *((int*)&con);
- jlong lval = val;
- lval = (lval << 32) | (lval & 0xFFFFFFFFl);
- return lval;
-}
-
-// Standard Sparc opcode form2 field breakdown
-static inline void emit2_19(CodeBuffer &cbuf, int f30, int f29, int f25, int f22, int f20, int f19, int f0 ) {
- f0 &= (1<<19)-1; // Mask displacement to 19 bits
- int op = (f30 << 30) |
- (f29 << 29) |
- (f25 << 25) |
- (f22 << 22) |
- (f20 << 20) |
- (f19 << 19) |
- (f0 << 0);
- cbuf.insts()->emit_int32(op);
-}
-
-// Standard Sparc opcode form2 field breakdown
-static inline void emit2_22(CodeBuffer &cbuf, int f30, int f25, int f22, int f0 ) {
- f0 >>= 10; // Drop 10 bits
- f0 &= (1<<22)-1; // Mask displacement to 22 bits
- int op = (f30 << 30) |
- (f25 << 25) |
- (f22 << 22) |
- (f0 << 0);
- cbuf.insts()->emit_int32(op);
-}
-
-// Standard Sparc opcode form3 field breakdown
-static inline void emit3(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, int f5, int f0 ) {
- int op = (f30 << 30) |
- (f25 << 25) |
- (f19 << 19) |
- (f14 << 14) |
- (f5 << 5) |
- (f0 << 0);
- cbuf.insts()->emit_int32(op);
-}
-
-// Standard Sparc opcode form3 field breakdown
-static inline void emit3_simm13(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, int simm13 ) {
- simm13 &= (1<<13)-1; // Mask to 13 bits
- int op = (f30 << 30) |
- (f25 << 25) |
- (f19 << 19) |
- (f14 << 14) |
- (1 << 13) | // bit to indicate immediate-mode
- (simm13<<0);
- cbuf.insts()->emit_int32(op);
-}
-
-static inline void emit3_simm10(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, int simm10 ) {
- simm10 &= (1<<10)-1; // Mask to 10 bits
- emit3_simm13(cbuf,f30,f25,f19,f14,simm10);
-}
-
-#ifdef ASSERT
-// Helper function for VerifyOops in emit_form3_mem_reg
-void verify_oops_warning(const MachNode *n, int ideal_op, int mem_op) {
- warning("VerifyOops encountered unexpected instruction:");
- n->dump(2);
- warning("Instruction has ideal_Opcode==Op_%s and op_ld==Op_%s \n", NodeClassNames[ideal_op], NodeClassNames[mem_op]);
-}
-#endif
-
-
-void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, int primary, int tertiary,
- int src1_enc, int disp32, int src2_enc, int dst_enc) {
-
-#ifdef ASSERT
- // The following code implements the +VerifyOops feature.
- // It verifies oop values which are loaded into or stored out of
- // the current method activation. +VerifyOops complements techniques
- // like ScavengeALot, because it eagerly inspects oops in transit,
- // as they enter or leave the stack, as opposed to ScavengeALot,
- // which inspects oops "at rest", in the stack or heap, at safepoints.
- // For this reason, +VerifyOops can sometimes detect bugs very close
- // to their point of creation. It can also serve as a cross-check
- // on the validity of oop maps, when used toegether with ScavengeALot.
-
- // It would be good to verify oops at other points, especially
- // when an oop is used as a base pointer for a load or store.
- // This is presently difficult, because it is hard to know when
- // a base address is biased or not. (If we had such information,
- // it would be easy and useful to make a two-argument version of
- // verify_oop which unbiases the base, and performs verification.)
-
- assert((uint)tertiary == 0xFFFFFFFF || tertiary == REGP_OP, "valid tertiary");
- bool is_verified_oop_base = false;
- bool is_verified_oop_load = false;
- bool is_verified_oop_store = false;
- int tmp_enc = -1;
- if (VerifyOops && src1_enc != R_SP_enc) {
- // classify the op, mainly for an assert check
- int st_op = 0, ld_op = 0;
- switch (primary) {
- case Assembler::stb_op3: st_op = Op_StoreB; break;
- case Assembler::sth_op3: st_op = Op_StoreC; break;
- case Assembler::stx_op3: // may become StoreP or stay StoreI or StoreD0
- case Assembler::stw_op3: st_op = Op_StoreI; break;
- case Assembler::std_op3: st_op = Op_StoreL; break;
- case Assembler::stf_op3: st_op = Op_StoreF; break;
- case Assembler::stdf_op3: st_op = Op_StoreD; break;
-
- case Assembler::ldsb_op3: ld_op = Op_LoadB; break;
- case Assembler::ldub_op3: ld_op = Op_LoadUB; break;
- case Assembler::lduh_op3: ld_op = Op_LoadUS; break;
- case Assembler::ldsh_op3: ld_op = Op_LoadS; break;
- case Assembler::ldx_op3: // may become LoadP or stay LoadI
- case Assembler::ldsw_op3: // may become LoadP or stay LoadI
- case Assembler::lduw_op3: ld_op = Op_LoadI; break;
- case Assembler::ldd_op3: ld_op = Op_LoadL; break;
- case Assembler::ldf_op3: ld_op = Op_LoadF; break;
- case Assembler::lddf_op3: ld_op = Op_LoadD; break;
- case Assembler::prefetch_op3: ld_op = Op_LoadI; break;
-
- default: ShouldNotReachHere();
- }
- if (tertiary == REGP_OP) {
- if (st_op == Op_StoreI) st_op = Op_StoreP;
- else if (ld_op == Op_LoadI) ld_op = Op_LoadP;
- else ShouldNotReachHere();
- if (st_op) {
- // a store
- // inputs are (0:control, 1:memory, 2:address, 3:value)
- Node* n2 = n->in(3);
- if (n2 != NULL) {
- const Type* t = n2->bottom_type();
- is_verified_oop_store = t->isa_oop_ptr() ? (t->is_ptr()->_offset==0) : false;
- }
- } else {
- // a load
- const Type* t = n->bottom_type();
- is_verified_oop_load = t->isa_oop_ptr() ? (t->is_ptr()->_offset==0) : false;
- }
- }
-
- if (ld_op) {
- // a Load
- // inputs are (0:control, 1:memory, 2:address)
- if (!(n->ideal_Opcode()==ld_op) && // Following are special cases
- !(n->ideal_Opcode()==Op_LoadPLocked && ld_op==Op_LoadP) &&
- !(n->ideal_Opcode()==Op_LoadI && ld_op==Op_LoadF) &&
- !(n->ideal_Opcode()==Op_LoadF && ld_op==Op_LoadI) &&
- !(n->ideal_Opcode()==Op_LoadRange && ld_op==Op_LoadI) &&
- !(n->ideal_Opcode()==Op_LoadKlass && ld_op==Op_LoadP) &&
- !(n->ideal_Opcode()==Op_LoadL && ld_op==Op_LoadI) &&
- !(n->ideal_Opcode()==Op_LoadL_unaligned && ld_op==Op_LoadI) &&
- !(n->ideal_Opcode()==Op_LoadD_unaligned && ld_op==Op_LoadF) &&
- !(n->ideal_Opcode()==Op_ConvI2F && ld_op==Op_LoadF) &&
- !(n->ideal_Opcode()==Op_ConvI2D && ld_op==Op_LoadF) &&
- !(n->ideal_Opcode()==Op_PrefetchAllocation && ld_op==Op_LoadI) &&
- !(n->ideal_Opcode()==Op_LoadVector && ld_op==Op_LoadD) &&
- !(n->rule() == loadUB_rule)) {
- verify_oops_warning(n, n->ideal_Opcode(), ld_op);
- }
- } else if (st_op) {
- // a Store
- // inputs are (0:control, 1:memory, 2:address, 3:value)
- if (!(n->ideal_Opcode()==st_op) && // Following are special cases
- !(n->ideal_Opcode()==Op_StoreCM && st_op==Op_StoreB) &&
- !(n->ideal_Opcode()==Op_StoreI && st_op==Op_StoreF) &&
- !(n->ideal_Opcode()==Op_StoreF && st_op==Op_StoreI) &&
- !(n->ideal_Opcode()==Op_StoreL && st_op==Op_StoreI) &&
- !(n->ideal_Opcode()==Op_StoreVector && st_op==Op_StoreD) &&
- !(n->ideal_Opcode()==Op_StoreD && st_op==Op_StoreI && n->rule() == storeD0_rule)) {
- verify_oops_warning(n, n->ideal_Opcode(), st_op);
- }
- }
-
- if (src2_enc == R_G0_enc && n->rule() != loadUB_rule && n->ideal_Opcode() != Op_StoreCM ) {
- Node* addr = n->in(2);
- if (!(addr->is_Mach() && addr->as_Mach()->ideal_Opcode() == Op_AddP)) {
- const TypeOopPtr* atype = addr->bottom_type()->isa_instptr(); // %%% oopptr?
- if (atype != NULL) {
- intptr_t offset = get_offset_from_base(n, atype, disp32);
- intptr_t offset_2 = get_offset_from_base_2(n, atype, disp32);
- if (offset != offset_2) {
- get_offset_from_base(n, atype, disp32);
- get_offset_from_base_2(n, atype, disp32);
- }
- assert(offset == offset_2, "different offsets");
- if (offset == disp32) {
- // we now know that src1 is a true oop pointer
- is_verified_oop_base = true;
- if (ld_op && src1_enc == dst_enc && ld_op != Op_LoadF && ld_op != Op_LoadD) {
- if( primary == Assembler::ldd_op3 ) {
- is_verified_oop_base = false; // Cannot 'ldd' into O7
- } else {
- tmp_enc = dst_enc;
- dst_enc = R_O7_enc; // Load into O7; preserve source oop
- assert(src1_enc != dst_enc, "");
- }
- }
- }
- if (st_op && (( offset == oopDesc::klass_offset_in_bytes())
- || offset == oopDesc::mark_offset_in_bytes())) {
- // loading the mark should not be allowed either, but
- // we don't check this since it conflicts with InlineObjectHash
- // usage of LoadINode to get the mark. We could keep the
- // check if we create a new LoadMarkNode
- // but do not verify the object before its header is initialized
- ShouldNotReachHere();
- }
- }
- }
- }
- }
-#endif
-
- uint instr = (Assembler::ldst_op << 30)
- | (dst_enc << 25)
- | (primary << 19)
- | (src1_enc << 14);
-
- uint index = src2_enc;
- int disp = disp32;
-
- if (src1_enc == R_SP_enc || src1_enc == R_FP_enc) {
- disp += STACK_BIAS;
- // Check that stack offset fits, load into O7 if not
- if (!Assembler::is_simm13(disp)) {
- C2_MacroAssembler _masm(&cbuf);
- __ set(disp, O7);
- if (index != R_G0_enc) {
- __ add(O7, reg_to_register_object(index), O7);
- }
- index = R_O7_enc;
- disp = 0;
- }
- }
-
- if( disp == 0 ) {
- // use reg-reg form
- // bit 13 is already zero
- instr |= index;
- } else {
- // use reg-imm form
- instr |= 0x00002000; // set bit 13 to one
- instr |= disp & 0x1FFF;
- }
-
- cbuf.insts()->emit_int32(instr);
-
-#ifdef ASSERT
- if (VerifyOops) {
- C2_MacroAssembler _masm(&cbuf);
- if (is_verified_oop_base) {
- __ verify_oop(reg_to_register_object(src1_enc));
- }
- if (is_verified_oop_store) {
- __ verify_oop(reg_to_register_object(dst_enc));
- }
- if (tmp_enc != -1) {
- __ mov(O7, reg_to_register_object(tmp_enc));
- }
- if (is_verified_oop_load) {
- __ verify_oop(reg_to_register_object(dst_enc));
- }
- }
-#endif
-}
-
-void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, RelocationHolder const& rspec, bool preserve_g2 = false) {
- // The method which records debug information at every safepoint
- // expects the call to be the first instruction in the snippet as
- // it creates a PcDesc structure which tracks the offset of a call
- // from the start of the codeBlob. This offset is computed as
- // code_end() - code_begin() of the code which has been emitted
- // so far.
- // In this particular case we have skirted around the problem by
- // putting the "mov" instruction in the delay slot but the problem
- // may bite us again at some other point and a cleaner/generic
- // solution using relocations would be needed.
- C2_MacroAssembler _masm(&cbuf);
- __ set_inst_mark();
-
- // We flush the current window just so that there is a valid stack copy
- // the fact that the current window becomes active again instantly is
- // not a problem there is nothing live in it.
-
-#ifdef ASSERT
- int startpos = __ offset();
-#endif /* ASSERT */
-
- __ call((address)entry_point, rspec);
-
- if (preserve_g2) __ delayed()->mov(G2, L7);
- else __ delayed()->nop();
-
- if (preserve_g2) __ mov(L7, G2);
-
-#ifdef ASSERT
- if (preserve_g2 && (VerifyCompiledCode || VerifyOops)) {
- // Trash argument dump slots.
- __ set(0xb0b8ac0db0b8ac0d, G1);
- __ mov(G1, G5);
- __ stx(G1, SP, STACK_BIAS + 0x80);
- __ stx(G1, SP, STACK_BIAS + 0x88);
- __ stx(G1, SP, STACK_BIAS + 0x90);
- __ stx(G1, SP, STACK_BIAS + 0x98);
- __ stx(G1, SP, STACK_BIAS + 0xA0);
- __ stx(G1, SP, STACK_BIAS + 0xA8);
- }
-#endif /*ASSERT*/
-}
-
-//=============================================================================
-// REQUIRED FUNCTIONALITY for encoding
-void emit_lo(CodeBuffer &cbuf, int val) { }
-void emit_hi(CodeBuffer &cbuf, int val) { }
-
-
-//=============================================================================
-const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
-
-int ConstantTable::calculate_table_base_offset() const {
- if (UseRDPCForConstantTableBase) {
- // The table base offset might be less but then it fits into
- // simm13 anyway and we are good (cf. MachConstantBaseNode::emit).
- return Assembler::min_simm13();
- } else {
- int offset = -(size() / 2);
- if (!Assembler::is_simm13(offset)) {
- offset = Assembler::min_simm13();
- }
- return offset;
- }
-}
-
-bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
-void MachConstantBaseNode::postalloc_expand(GrowableArray *nodes, PhaseRegAlloc *ra_) {
- ShouldNotReachHere();
-}
-
-void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
- Compile* C = ra_->C;
- ConstantTable& constant_table = C->output()->constant_table();
- C2_MacroAssembler _masm(&cbuf);
-
- Register r = as_Register(ra_->get_encode(this));
- CodeSection* consts_section = __ code()->consts();
- int consts_size = consts_section->align_at_start(consts_section->size());
- assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size);
-
- if (UseRDPCForConstantTableBase) {
- // For the following RDPC logic to work correctly the consts
- // section must be allocated right before the insts section. This
- // assert checks for that. The layout and the SECT_* constants
- // are defined in src/share/vm/asm/codeBuffer.hpp.
- assert(CodeBuffer::SECT_CONSTS + 1 == CodeBuffer::SECT_INSTS, "must be");
- int insts_offset = __ offset();
-
- // Layout:
- //
- // |----------- consts section ------------|----------- insts section -----------...
- // |------ constant table -----|- padding -|------------------x----
- // \ current PC (RDPC instruction)
- // |<------------- consts_size ----------->|<- insts_offset ->|
- // \ table base
- // The table base offset is later added to the load displacement
- // so it has to be negative.
- int table_base_offset = -(consts_size + insts_offset);
- int disp;
-
- // If the displacement from the current PC to the constant table
- // base fits into simm13 we set the constant table base to the
- // current PC.
- if (Assembler::is_simm13(table_base_offset)) {
- constant_table.set_table_base_offset(table_base_offset);
- disp = 0;
- } else {
- // Otherwise we set the constant table base offset to the
- // maximum negative displacement of load instructions to keep
- // the disp as small as possible:
- //
- // |<------------- consts_size ----------->|<- insts_offset ->|
- // |<--------- min_simm13 --------->|<-------- disp --------->|
- // \ table base
- table_base_offset = Assembler::min_simm13();
- constant_table.set_table_base_offset(table_base_offset);
- disp = (consts_size + insts_offset) + table_base_offset;
- }
-
- __ rdpc(r);
-
- if (disp == 0) {
- // Emitting an additional 'nop' instruction in order not to cause a code
- // size adjustment in the code following the table setup (if the instruction
- // immediately following after this section is a CTI).
- __ nop();
- }
- else {
- assert(r != O7, "need temporary");
- __ sub(r, __ ensure_simm13_or_reg(disp, O7), r);
- }
- }
- else {
- // Materialize the constant table base.
- address baseaddr = consts_section->start() + -(constant_table.table_base_offset());
- RelocationHolder rspec = internal_word_Relocation::spec(baseaddr);
- AddressLiteral base(baseaddr, rspec);
- __ set(base, r);
- }
-}
-
-uint MachConstantBaseNode::size(PhaseRegAlloc*) const {
- if (UseRDPCForConstantTableBase) {
- // This is really the worst case but generally it's only 1 instruction.
- return (1 /*rdpc*/ + 1 /*sub*/ + MacroAssembler::worst_case_insts_for_set()) * BytesPerInstWord;
- } else {
- return MacroAssembler::worst_case_insts_for_set() * BytesPerInstWord;
- }
-}
-
-#ifndef PRODUCT
-void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
- char reg[128];
- ra_->dump_register(this, reg);
- if (UseRDPCForConstantTableBase) {
- st->print("RDPC %s\t! constant table base", reg);
- } else {
- st->print("SET &constanttable,%s\t! constant table base", reg);
- }
-}
-#endif
-
-
-//=============================================================================
-
-#ifndef PRODUCT
-void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
- Compile* C = ra_->C;
-
- for (int i = 0; i < OptoPrologueNops; i++) {
- st->print_cr("NOP"); st->print("\t");
- }
-
- if( VerifyThread ) {
- st->print_cr("Verify_Thread"); st->print("\t");
- }
-
- size_t framesize = C->output()->frame_size_in_bytes();
- int bangsize = C->output()->bang_size_in_bytes();
-
- // Calls to C2R adapters often do not accept exceptional returns.
- // We require that their callers must bang for them. But be careful, because
- // some VM calls (such as call site linkage) can use several kilobytes of
- // stack. But the stack safety zone should account for that.
- // See bugs 4446381, 4468289, 4497237.
- if (C->output()->need_stack_bang(bangsize)) {
- st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
- }
-
- if (Assembler::is_simm13(-framesize)) {
- st->print ("SAVE R_SP,-" SIZE_FORMAT ",R_SP",framesize);
- } else {
- st->print_cr("SETHI R_SP,hi%%(-" SIZE_FORMAT "),R_G3",framesize); st->print("\t");
- st->print_cr("ADD R_G3,lo%%(-" SIZE_FORMAT "),R_G3",framesize); st->print("\t");
- st->print ("SAVE R_SP,R_G3,R_SP");
- }
-
-}
-#endif
-
-void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
- Compile* C = ra_->C;
- C2_MacroAssembler _masm(&cbuf);
-
- for (int i = 0; i < OptoPrologueNops; i++) {
- __ nop();
- }
-
- __ verify_thread();
-
- size_t framesize = C->output()->frame_size_in_bytes();
- assert(framesize >= 16*wordSize, "must have room for reg. save area");
- assert(framesize%(2*wordSize) == 0, "must preserve 2*wordSize alignment");
- int bangsize = C->output()->bang_size_in_bytes();
-
- // Calls to C2R adapters often do not accept exceptional returns.
- // We require that their callers must bang for them. But be careful, because
- // some VM calls (such as call site linkage) can use several kilobytes of
- // stack. But the stack safety zone should account for that.
- // See bugs 4446381, 4468289, 4497237.
- if (C->output()->need_stack_bang(bangsize)) {
- __ generate_stack_overflow_check(bangsize);
- }
-
- if (Assembler::is_simm13(-framesize)) {
- __ save(SP, -framesize, SP);
- } else {
- __ sethi(-framesize & ~0x3ff, G3);
- __ add(G3, -framesize & 0x3ff, G3);
- __ save(SP, G3, SP);
- }
- C->output()->set_frame_complete( __ offset() );
-
- if (!UseRDPCForConstantTableBase && C->has_mach_constant_base_node()) {
- // NOTE: We set the table base offset here because users might be
- // emitted before MachConstantBaseNode.
- ConstantTable& constant_table = C->output()->constant_table();
- constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
- }
-}
-
-uint MachPrologNode::size(PhaseRegAlloc *ra_) const {
- return MachNode::size(ra_);
-}
-
-int MachPrologNode::reloc() const {
- return 10; // a large enough number
-}
-
-//=============================================================================
-#ifndef PRODUCT
-void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
- Compile* C = ra_->C;
-
- if(do_polling() && ra_->C->is_method_compilation()) {
- st->print("LDX [R_G2 + #poll_offset],L0\t! Load local polling address\n\t");
- st->print("LDX [L0],G0\t!Poll for Safepointing\n\t");
- }
-
- if(do_polling()) {
- if (UseCBCond && !ra_->C->is_method_compilation()) {
- st->print("NOP\n\t");
- }
- st->print("RET\n\t");
- }
-
- st->print("RESTORE");
-}
-#endif
-
-void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
- C2_MacroAssembler _masm(&cbuf);
- Compile* C = ra_->C;
-
- __ verify_thread();
-
- if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
- __ reserved_stack_check();
- }
-
- // If this does safepoint polling, then do it here
- if(do_polling() && ra_->C->is_method_compilation()) {
- __ ld_ptr(Address(G2_thread, Thread::polling_page_offset()), L0);
- __ relocate(relocInfo::poll_return_type);
- __ ld_ptr(L0, 0, G0);
- }
-
- // If this is a return, then stuff the restore in the delay slot
- if(do_polling()) {
- if (UseCBCond && !ra_->C->is_method_compilation()) {
- // Insert extra padding for the case when the epilogue is preceded by
- // a cbcond jump, which can't be followed by a CTI instruction
- __ nop();
- }
- __ ret();
- __ delayed()->restore();
- } else {
- __ restore();
- }
-}
-
-uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
- return MachNode::size(ra_);
-}
-
-int MachEpilogNode::reloc() const {
- return 16; // a large enough number
-}
-
-const Pipeline * MachEpilogNode::pipeline() const {
- return MachNode::pipeline_class();
-}
-
-//=============================================================================
-
-// Figure out which register class each belongs in: rc_int, rc_float, rc_stack
-enum RC { rc_bad, rc_int, rc_float, rc_stack };
-static enum RC rc_class( OptoReg::Name reg ) {
- if (!OptoReg::is_valid(reg)) return rc_bad;
- if (OptoReg::is_stack(reg)) return rc_stack;
- VMReg r = OptoReg::as_VMReg(reg);
- if (r->is_Register()) return rc_int;
- assert(r->is_FloatRegister(), "must be");
- return rc_float;
-}
-
-#ifndef PRODUCT
-ATTRIBUTE_PRINTF(2, 3)
-static void print_helper(outputStream* st, const char* format, ...) {
- const int tab_size = 8;
- if (st->position() > tab_size) {
- st->cr();
- st->sp();
- }
- va_list ap;
- va_start(ap, format);
- st->vprint(format, ap);
- va_end(ap);
-}
-#endif // !PRODUCT
-
-static void impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool is_load, int offset, int reg, int opcode, const char *op_str, outputStream* st) {
- if (cbuf) {
- emit_form3_mem_reg(*cbuf, ra, mach, opcode, -1, R_SP_enc, offset, 0, Matcher::_regEncode[reg]);
- }
-#ifndef PRODUCT
- else {
- if (is_load) {
- print_helper(st, "%s [R_SP + #%d],R_%s\t! spill", op_str, offset, OptoReg::regname(reg));
- } else {
- print_helper(st, "%s R_%s,[R_SP + #%d]\t! spill", op_str, OptoReg::regname(reg), offset);
- }
- }
-#endif
-}
-
-static void impl_mov_helper(CodeBuffer *cbuf, int src, int dst, int op1, int op2, const char *op_str, outputStream* st) {
- if (cbuf) {
- emit3(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src]);
- }
-#ifndef PRODUCT
- else {
- print_helper(st, "%s R_%s,R_%s\t! spill", op_str, OptoReg::regname(src), OptoReg::regname(dst));
- }
-#endif
-}
-
-static void mach_spill_copy_implementation_helper(const MachNode* mach,
- CodeBuffer *cbuf,
- PhaseRegAlloc *ra_,
- outputStream* st) {
- // Get registers to move
- OptoReg::Name src_second = ra_->get_reg_second(mach->in(1));
- OptoReg::Name src_first = ra_->get_reg_first(mach->in(1));
- OptoReg::Name dst_second = ra_->get_reg_second(mach);
- OptoReg::Name dst_first = ra_->get_reg_first(mach);
-
- enum RC src_second_rc = rc_class(src_second);
- enum RC src_first_rc = rc_class(src_first);
- enum RC dst_second_rc = rc_class(dst_second);
- enum RC dst_first_rc = rc_class(dst_first);
-
- assert(OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register");
-
- if (src_first == dst_first && src_second == dst_second) {
- return; // Self copy, no move
- }
-
- // --------------------------------------
- // Check for mem-mem move. Load into unused float registers and fall into
- // the float-store case.
- if (src_first_rc == rc_stack && dst_first_rc == rc_stack) {
- int offset = ra_->reg2offset(src_first);
- // Further check for aligned-adjacent pair, so we can use a double load
- if ((src_first&1) == 0 && src_first+1 == src_second) {
- src_second = OptoReg::Name(R_F31_num);
- src_second_rc = rc_float;
- impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::lddf_op3, "LDDF", st);
- } else {
- impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::ldf_op3, "LDF ", st);
- }
- src_first = OptoReg::Name(R_F30_num);
- src_first_rc = rc_float;
- }
-
- if( src_second_rc == rc_stack && dst_second_rc == rc_stack ) {
- int offset = ra_->reg2offset(src_second);
- impl_helper(mach, cbuf, ra_, true, offset, R_F31_num, Assembler::ldf_op3, "LDF ", st);
- src_second = OptoReg::Name(R_F31_num);
- src_second_rc = rc_float;
- }
-
- // --------------------------------------
- // Check for float->int copy; requires a trip through memory
- if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS < 3) {
- int offset = frame::register_save_words*wordSize;
- if (cbuf) {
- emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16);
- impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st);
- impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st);
- emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16);
- }
-#ifndef PRODUCT
- else {
- print_helper(st, "SUB R_SP,16,R_SP");
- impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st);
- impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st);
- print_helper(st, "ADD R_SP,16,R_SP");
- }
-#endif
- }
-
- // Check for float->int copy on T4
- if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS >= 3) {
- // Further check for aligned-adjacent pair, so we can use a double move
- if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
- impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mdtox_opf, "MOVDTOX", st);
- return;
- }
- impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mstouw_opf, "MOVSTOUW", st);
- }
- // Check for int->float copy on T4
- if (src_first_rc == rc_int && dst_first_rc == rc_float && UseVIS >= 3) {
- // Further check for aligned-adjacent pair, so we can use a double move
- if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
- impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mxtod_opf, "MOVXTOD", st);
- return;
- }
- impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mwtos_opf, "MOVWTOS", st);
- }
-
- // --------------------------------------
- // In the 32-bit 1-reg-longs build ONLY, I see mis-aligned long destinations.
- // In such cases, I have to do the big-endian swap. For aligned targets, the
- // hardware does the flop for me. Doubles are always aligned, so no problem
- // there. Misaligned sources only come from native-long-returns (handled
- // special below).
-
- // --------------------------------------
- // Check for integer reg-reg copy
- if (src_first_rc == rc_int && dst_first_rc == rc_int) {
- // Else normal reg-reg copy
- assert(src_second != dst_first, "smashed second before evacuating it");
- impl_mov_helper(cbuf, src_first, dst_first, Assembler::or_op3, 0, "MOV ", st);
- assert((src_first & 1) == 0 && (dst_first & 1) == 0, "never move second-halves of int registers");
- // This moves an aligned adjacent pair.
- // See if we are done.
- if (src_first + 1 == src_second && dst_first + 1 == dst_second) {
- return;
- }
- }
-
- // Check for integer store
- if (src_first_rc == rc_int && dst_first_rc == rc_stack) {
- int offset = ra_->reg2offset(dst_first);
- // Further check for aligned-adjacent pair, so we can use a double store
- if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
- impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stx_op3, "STX ", st);
- return;
- }
- impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stw_op3, "STW ", st);
- }
-
- // Check for integer load
- if (dst_first_rc == rc_int && src_first_rc == rc_stack) {
- int offset = ra_->reg2offset(src_first);
- // Further check for aligned-adjacent pair, so we can use a double load
- if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
- impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldx_op3, "LDX ", st);
- return;
- }
- impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st);
- }
-
- // Check for float reg-reg copy
- if (src_first_rc == rc_float && dst_first_rc == rc_float) {
- // Further check for aligned-adjacent pair, so we can use a double move
- if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
- impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovd_opf, "FMOVD", st);
- return;
- }
- impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovs_opf, "FMOVS", st);
- }
-
- // Check for float store
- if (src_first_rc == rc_float && dst_first_rc == rc_stack) {
- int offset = ra_->reg2offset(dst_first);
- // Further check for aligned-adjacent pair, so we can use a double store
- if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
- impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stdf_op3, "STDF", st);
- return;
- }
- impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st);
- }
-
- // Check for float load
- if (dst_first_rc == rc_float && src_first_rc == rc_stack) {
- int offset = ra_->reg2offset(src_first);
- // Further check for aligned-adjacent pair, so we can use a double load
- if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) {
- impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lddf_op3, "LDDF", st);
- return;
- }
- impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldf_op3, "LDF ", st);
- }
-
- // --------------------------------------------------------------------
- // Check for hi bits still needing moving. Only happens for misaligned
- // arguments to native calls.
- if (src_second == dst_second) {
- return; // Self copy; no move
- }
- assert(src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad");
-
- Unimplemented();
-}
-
-uint MachSpillCopyNode::implementation(CodeBuffer *cbuf,
- PhaseRegAlloc *ra_,
- bool do_size,
- outputStream* st) const {
- assert(!do_size, "not supported");
- mach_spill_copy_implementation_helper(this, cbuf, ra_, st);
- return 0;
-}
-
-#ifndef PRODUCT
-void MachSpillCopyNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
- implementation( NULL, ra_, false, st );
-}
-#endif
-
-void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
- implementation( &cbuf, ra_, false, NULL );
-}
-
-uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const {
- return MachNode::size(ra_);
-}
-
-//=============================================================================
-#ifndef PRODUCT
-void MachNopNode::format(PhaseRegAlloc *, outputStream *st) const {
- st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count);
-}
-#endif
-
-void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *) const {
- C2_MacroAssembler _masm(&cbuf);
- for (int i = 0; i < _count; i += 1) {
- __ nop();
- }
-}
-
-uint MachNopNode::size(PhaseRegAlloc *ra_) const {
- return 4 * _count;
-}
-
-
-//=============================================================================
-#ifndef PRODUCT
-void BoxLockNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
- int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
- int reg = ra_->get_reg_first(this);
- st->print("LEA [R_SP+#%d+BIAS],%s",offset,Matcher::regName[reg]);
-}
-#endif
-
-void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
- C2_MacroAssembler _masm(&cbuf);
- int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()) + STACK_BIAS;
- int reg = ra_->get_encode(this);
-
- if (Assembler::is_simm13(offset)) {
- __ add(SP, offset, reg_to_register_object(reg));
- } else {
- __ set(offset, O7);
- __ add(SP, O7, reg_to_register_object(reg));
- }
-}
-
-uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
- // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
- assert(ra_ == ra_->C->regalloc(), "sanity");
- return ra_->C->output()->scratch_emit_size(this);
-}
-
-//=============================================================================
-#ifndef PRODUCT
-void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
- st->print_cr("\nUEP:");
- if (UseCompressedClassPointers) {
- assert(Universe::heap() != NULL, "java heap should be initialized");
- st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass");
- if (CompressedKlassPointers::base() != 0) {
- st->print_cr("\tSET CompressedKlassPointers::base,R_G6_heap_base");
- if (CompressedKlassPointers::shift() != 0) {
- st->print_cr("\tSLL R_G5,CompressedKlassPointers::shift,R_G5");
- }
- st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5");
- st->print_cr("\tSET CompressedOops::ptrs_base,R_G6_heap_base");
- } else {
- st->print_cr("\tSLL R_G5,CompressedKlassPointers::shift,R_G5");
- }
- } else {
- st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check");
- }
- st->print_cr("\tCMP R_G5,R_G3" );
- st->print ("\tTne xcc,R_G0+ST_RESERVED_FOR_USER_0+2");
-}
-#endif
-
-void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
- C2_MacroAssembler _masm(&cbuf);
- Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
- Register temp_reg = G3;
- assert( G5_ic_reg != temp_reg, "conflicting registers" );
-
- // Load klass from receiver
- __ load_klass(O0, temp_reg);
- // Compare against expected klass
- __ cmp(temp_reg, G5_ic_reg);
- // Branch to miss code, checks xcc or icc depending
- __ trap(Assembler::notEqual, Assembler::ptr_cc, G0, ST_RESERVED_FOR_USER_0+2);
-}
-
-uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
- return MachNode::size(ra_);
-}
-
-
-//=============================================================================
-
-
-// Emit exception handler code.
-int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) {
- Register temp_reg = G3;
- AddressLiteral exception_blob(OptoRuntime::exception_blob()->entry_point());
- C2_MacroAssembler _masm(&cbuf);
-
- address base = __ start_a_stub(size_exception_handler());
- if (base == NULL) {
- ciEnv::current()->record_failure("CodeCache is full");
- return 0; // CodeBuffer::expand failed
- }
-
- int offset = __ offset();
-
- __ JUMP(exception_blob, temp_reg, 0); // sethi;jmp
- __ delayed()->nop();
-
- assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
-
- __ end_a_stub();
-
- return offset;
-}
-
-int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) {
- // Can't use any of the current frame's registers as we may have deopted
- // at a poll and everything (including G3) can be live.
- Register temp_reg = L0;
- AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack());
- C2_MacroAssembler _masm(&cbuf);
-
- address base = __ start_a_stub(size_deopt_handler());
- if (base == NULL) {
- ciEnv::current()->record_failure("CodeCache is full");
- return 0; // CodeBuffer::expand failed
- }
-
- int offset = __ offset();
- __ save_frame(0);
- __ JUMP(deopt_blob, temp_reg, 0); // sethi;jmp
- __ delayed()->restore();
-
- assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow");
-
- __ end_a_stub();
- return offset;
-
-}
-
-// Given a register encoding, produce a Integer Register object
-static Register reg_to_register_object(int register_encoding) {
- assert(L5->encoding() == R_L5_enc && G1->encoding() == R_G1_enc, "right coding");
- return as_Register(register_encoding);
-}
-
-// Given a register encoding, produce a single-precision Float Register object
-static FloatRegister reg_to_SingleFloatRegister_object(int register_encoding) {
- assert(F5->encoding(FloatRegisterImpl::S) == R_F5_enc && F12->encoding(FloatRegisterImpl::S) == R_F12_enc, "right coding");
- return as_SingleFloatRegister(register_encoding);
-}
-
-// Given a register encoding, produce a double-precision Float Register object
-static FloatRegister reg_to_DoubleFloatRegister_object(int register_encoding) {
- assert(F4->encoding(FloatRegisterImpl::D) == R_F4_enc, "right coding");
- assert(F32->encoding(FloatRegisterImpl::D) == R_D32_enc, "right coding");
- return as_DoubleFloatRegister(register_encoding);
-}
-
-const bool Matcher::match_rule_supported(int opcode) {
- if (!has_match_rule(opcode))
- return false;
-
- switch (opcode) {
- case Op_CountLeadingZerosI:
- case Op_CountLeadingZerosL:
- case Op_CountTrailingZerosI:
- case Op_CountTrailingZerosL:
- case Op_PopCountI:
- case Op_PopCountL:
- if (!UsePopCountInstruction)
- return false;
- case Op_CompareAndSwapL:
- case Op_CompareAndSwapP:
- if (!VM_Version::supports_cx8())
- return false;
- break;
- }
-
- return true; // Per default match rules are supported.
-}
-
-const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) {
-
- // TODO
- // identify extra cases that we might want to provide match rules for
- // e.g. Op_ vector nodes and other intrinsics while guarding with vlen
- bool ret_value = match_rule_supported(opcode);
- // Add rules here.
-
- return ret_value; // Per default match rules are supported.
-}
-
-const bool Matcher::has_predicated_vectors(void) {
- return false;
-}
-
-const int Matcher::float_pressure(int default_pressure_threshold) {
- return default_pressure_threshold;
-}
-
-int Matcher::regnum_to_fpu_offset(int regnum) {
- return regnum - 32; // The FP registers are in the second chunk
-}
-
-#ifdef ASSERT
-address last_rethrow = NULL; // debugging aid for Rethrow encoding
-#endif
-
-// Vector width in bytes
-const int Matcher::vector_width_in_bytes(BasicType bt) {
- assert(MaxVectorSize == 8, "");
- return 8;
-}
-
-// Vector ideal reg
-const uint Matcher::vector_ideal_reg(int size) {
- assert(MaxVectorSize == 8, "");
- return Op_RegD;
-}
-
-// Limits on vector size (number of elements) loaded into vector.
-const int Matcher::max_vector_size(const BasicType bt) {
- assert(is_java_primitive(bt), "only primitive type vectors");
- return vector_width_in_bytes(bt)/type2aelembytes(bt);
-}
-
-const int Matcher::min_vector_size(const BasicType bt) {
- return max_vector_size(bt); // Same as max.
-}
-
-// SPARC doesn't support misaligned vectors store/load.
-const bool Matcher::misaligned_vectors_ok() {
- return false;
-}
-
-// Current (2013) SPARC platforms need to read original key
-// to construct decryption expanded key
-const bool Matcher::pass_original_key_for_aes() {
- return true;
-}
-
-// NOTE: All currently supported SPARC HW provides fast conversion.
-const bool Matcher::convL2FSupported(void) { return true; }
-
-// Is this branch offset short enough that a short branch can be used?
-//
-// NOTE: If the platform does not provide any short branch variants, then
-// this method should return false for offset 0.
-bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
- // The passed offset is relative to address of the branch.
- // Don't need to adjust the offset.
- return UseCBCond && Assembler::is_simm12(offset);
-}
-
-const bool Matcher::isSimpleConstant64(jlong value) {
- // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?.
- // Depends on optimizations in MacroAssembler::setx.
- int hi = (int)(value >> 32);
- int lo = (int)(value & ~0);
- return (hi == 0) || (hi == -1) || (lo == 0);
-}
-
-// No scaling for the parameter the ClearArray node.
-const bool Matcher::init_array_count_is_in_bytes = true;
-
-// No additional cost for CMOVL.
-const int Matcher::long_cmove_cost() { return 0; }
-
-// CMOVF/CMOVD are expensive on e.g., T4 and SPARC64.
-const int Matcher::float_cmove_cost() {
- return VM_Version::has_fast_cmove() ? 0 : ConditionalMoveLimit;
-}
-
-// Does the CPU require late expand (see block.cpp for description of late expand)?
-const bool Matcher::require_postalloc_expand = false;
-
-// Do we need to mask the count passed to shift instructions or does
-// the cpu only look at the lower 5/6 bits anyway?
-const bool Matcher::need_masked_shift_count = false;
-
-// No support for generic vector operands.
-const bool Matcher::supports_generic_vector_operands = false;
-
-MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) {
- ShouldNotReachHere(); // generic vector operands not supported
- return NULL;
-}
-
-bool Matcher::is_generic_reg2reg_move(MachNode* m) {
- ShouldNotReachHere(); // generic vector operands not supported
- return false;
-}
-
-bool Matcher::is_generic_vector(MachOper* opnd) {
- ShouldNotReachHere(); // generic vector operands not supported
- return false;
-}
-
-bool Matcher::narrow_oop_use_complex_address() {
- assert(UseCompressedOops, "only for compressed oops code");
- return false;
-}
-
-bool Matcher::narrow_klass_use_complex_address() {
- assert(UseCompressedClassPointers, "only for compressed klass code");
- return false;
-}
-
-bool Matcher::const_oop_prefer_decode() {
- // TODO: Check if loading ConP from TOC in heap-based mode is better:
- // Prefer ConN+DecodeN over ConP in simple compressed oops mode.
- // return CompressedOops::base() == NULL;
- return true;
-}
-
-bool Matcher::const_klass_prefer_decode() {
- // TODO: Check if loading ConP from TOC in heap-based mode is better:
- // Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode.
- // return CompressedKlassPointers::base() == NULL;
- return true;
-}
-
-// Is it better to copy float constants, or load them directly from memory?
-// Intel can load a float constant from a direct address, requiring no
-// extra registers. Most RISCs will have to materialize an address into a
-// register first, so they would do better to copy the constant from stack.
-const bool Matcher::rematerialize_float_constants = false;
-
-// If CPU can load and store mis-aligned doubles directly then no fixup is
-// needed. Else we split the double into 2 integer pieces and move it
-// piece-by-piece. Only happens when passing doubles into C code as the
-// Java calling convention forces doubles to be aligned.
-const bool Matcher::misaligned_doubles_ok = true;
-
-// No-op on SPARC.
-void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {
-}
-
-// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode.
-const bool Matcher::strict_fp_requires_explicit_rounding = false;
-
-// Are floats converted to double when stored to stack during deoptimization?
-// Sparc does not handle callee-save floats.
-bool Matcher::float_in_double() { return false; }
-
-// Do ints take an entire long register or just half?
-// Note that we if-def off of _LP64.
-// The relevant question is how the int is callee-saved. In _LP64
-// the whole long is written but de-opt'ing will have to extract
-// the relevant 32 bits, in not-_LP64 only the low 32 bits is written.
-const bool Matcher::int_in_long = true;
-
-// Return whether or not this register is ever used as an argument. This
-// function is used on startup to build the trampoline stubs in generateOptoStub.
-// Registers not mentioned will be killed by the VM call in the trampoline, and
-// arguments in those registers not be available to the callee.
-bool Matcher::can_be_java_arg( int reg ) {
- // Standard sparc 6 args in registers
- if( reg == R_I0_num ||
- reg == R_I1_num ||
- reg == R_I2_num ||
- reg == R_I3_num ||
- reg == R_I4_num ||
- reg == R_I5_num ) return true;
- // 64-bit builds can pass 64-bit pointers and longs in
- // the high I registers
- if( reg == R_I0H_num ||
- reg == R_I1H_num ||
- reg == R_I2H_num ||
- reg == R_I3H_num ||
- reg == R_I4H_num ||
- reg == R_I5H_num ) return true;
-
- if ((UseCompressedOops) && (reg == R_G6_num || reg == R_G6H_num)) {
- return true;
- }
-
- // A few float args in registers
- if( reg >= R_F0_num && reg <= R_F7_num ) return true;
-
- return false;
-}
-
-bool Matcher::is_spillable_arg( int reg ) {
- return can_be_java_arg(reg);
-}
-
-bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
- // Use hardware SDIVX instruction when it is
- // faster than a code which use multiply.
- return VM_Version::has_fast_idiv();
-}
-
-// Register for DIVI projection of divmodI
-RegMask Matcher::divI_proj_mask() {
- ShouldNotReachHere();
- return RegMask();
-}
-
-// Register for MODI projection of divmodI
-RegMask Matcher::modI_proj_mask() {
- ShouldNotReachHere();
- return RegMask();
-}
-
-// Register for DIVL projection of divmodL
-RegMask Matcher::divL_proj_mask() {
- ShouldNotReachHere();
- return RegMask();
-}
-
-// Register for MODL projection of divmodL
-RegMask Matcher::modL_proj_mask() {
- ShouldNotReachHere();
- return RegMask();
-}
-
-const RegMask Matcher::method_handle_invoke_SP_save_mask() {
- return L7_REGP_mask();
-}
-
-
-const bool Matcher::convi2l_type_required = true;
-
-// Should the matcher clone input 'm' of node 'n'?
-bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
- return false;
-}
-
-// Should the Matcher clone shifts on addressing modes, expecting them
-// to be subsumed into complex addressing expressions or compute them
-// into registers?
-bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) {
- return clone_base_plus_offset_address(m, mstack, address_visited);
-}
-
-void Compile::reshape_address(AddPNode* addp) {
-}
-
-%}
-
-
-// The intptr_t operand types, defined by textual substitution.
-// (Cf. opto/type.hpp. This lets us avoid many, many other ifdefs.)
-#define immX immL
-#define immX13 immL13
-#define immX13m7 immL13m7
-#define iRegX iRegL
-#define g1RegX g1RegL
-
-//----------ENCODING BLOCK-----------------------------------------------------
-// This block specifies the encoding classes used by the compiler to output
-// byte streams. Encoding classes are parameterized macros used by
-// Machine Instruction Nodes in order to generate the bit encoding of the
-// instruction. Operands specify their base encoding interface with the
-// interface keyword. There are currently supported four interfaces,
-// REG_INTER, CONST_INTER, MEMORY_INTER, & COND_INTER. REG_INTER causes an
-// operand to generate a function which returns its register number when
-// queried. CONST_INTER causes an operand to generate a function which
-// returns the value of the constant when queried. MEMORY_INTER causes an
-// operand to generate four functions which return the Base Register, the
-// Index Register, the Scale Value, and the Offset Value of the operand when
-// queried. COND_INTER causes an operand to generate six functions which
-// return the encoding code (ie - encoding bits for the instruction)
-// associated with each basic boolean condition for a conditional instruction.
-//
-// Instructions specify two basic values for encoding. Again, a function
-// is available to check if the constant displacement is an oop. They use the
-// ins_encode keyword to specify their encoding classes (which must be
-// a sequence of enc_class names, and their parameters, specified in
-// the encoding block), and they use the
-// opcode keyword to specify, in order, their primary, secondary, and
-// tertiary opcode. Only the opcode sections which a particular instruction
-// needs for encoding need to be specified.
-encode %{
- enc_class enc_untested %{
-#ifdef ASSERT
- C2_MacroAssembler _masm(&cbuf);
- __ untested("encoding");
-#endif
- %}
-
- enc_class form3_mem_reg( memory mem, iRegI dst ) %{
- emit_form3_mem_reg(cbuf, ra_, this, $primary, $tertiary,
- $mem$$base, $mem$$disp, $mem$$index, $dst$$reg);
- %}
-
- enc_class simple_form3_mem_reg( memory mem, iRegI dst ) %{
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1,
- $mem$$base, $mem$$disp, $mem$$index, $dst$$reg);
- %}
-
- enc_class form3_mem_prefetch_read( memory mem ) %{
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1,
- $mem$$base, $mem$$disp, $mem$$index, 0/*prefetch function many-reads*/);
- %}
-
- enc_class form3_mem_prefetch_write( memory mem ) %{
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1,
- $mem$$base, $mem$$disp, $mem$$index, 2/*prefetch function many-writes*/);
- %}
-
- enc_class form3_mem_reg_long_unaligned_marshal( memory mem, iRegL reg ) %{
- assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4");
- assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4");
- guarantee($mem$$index == R_G0_enc, "double index?");
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, R_O7_enc );
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg );
- emit3_simm13( cbuf, Assembler::arith_op, $reg$$reg, Assembler::sllx_op3, $reg$$reg, 0x1020 );
- emit3( cbuf, Assembler::arith_op, $reg$$reg, Assembler::or_op3, $reg$$reg, 0, R_O7_enc );
- %}
-
- enc_class form3_mem_reg_double_unaligned( memory mem, RegD_low reg ) %{
- assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4");
- assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4");
- guarantee($mem$$index == R_G0_enc, "double index?");
- // Load long with 2 instructions
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg+0 );
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, $reg$$reg+1 );
- %}
-
- //%%% form3_mem_plus_4_reg is a hack--get rid of it
- enc_class form3_mem_plus_4_reg( memory mem, iRegI dst ) %{
- guarantee($mem$$disp, "cannot offset a reg-reg operand by 4");
- emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp + 4, $mem$$index, $dst$$reg);
- %}
-
- enc_class form3_g0_rs2_rd_move( iRegI rs2, iRegI rd ) %{
- // Encode a reg-reg copy. If it is useless, then empty encoding.
- if( $rs2$$reg != $rd$$reg )
- emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, 0, $rs2$$reg );
- %}
-
- // Target lo half of long
- enc_class form3_g0_rs2_rd_move_lo( iRegI rs2, iRegL rd ) %{
- // Encode a reg-reg copy. If it is useless, then empty encoding.
- if( $rs2$$reg != LONG_LO_REG($rd$$reg) )
- emit3( cbuf, Assembler::arith_op, LONG_LO_REG($rd$$reg), Assembler::or_op3, 0, 0, $rs2$$reg );
- %}
-
- // Source lo half of long
- enc_class form3_g0_rs2_rd_move_lo2( iRegL rs2, iRegI rd ) %{
- // Encode a reg-reg copy. If it is useless, then empty encoding.
- if( LONG_LO_REG($rs2$$reg) != $rd$$reg )
- emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, 0, LONG_LO_REG($rs2$$reg) );
- %}
-
- // Target hi half of long
- enc_class form3_rs1_rd_copysign_hi( iRegI rs1, iRegL rd ) %{
- emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::sra_op3, $rs1$$reg, 31 );
- %}
-
- // Source lo half of long, and leave it sign extended.
- enc_class form3_rs1_rd_signextend_lo1( iRegL rs1, iRegI rd ) %{
- // Sign extend low half
- emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::sra_op3, $rs1$$reg, 0, 0 );
- %}
-
- // Source hi half of long, and leave it sign extended.
- enc_class form3_rs1_rd_copy_hi1( iRegL rs1, iRegI rd ) %{
- // Shift high half to low half
- emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::srlx_op3, $rs1$$reg, 32 );
- %}
-
- // Source hi half of long
- enc_class form3_g0_rs2_rd_move_hi2( iRegL rs2, iRegI rd ) %{
- // Encode a reg-reg copy. If it is useless, then empty encoding.
- if( LONG_HI_REG($rs2$$reg) != $rd$$reg )
- emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, 0, LONG_HI_REG($rs2$$reg) );
- %}
-
- enc_class form3_rs1_rs2_rd( iRegI rs1, iRegI rs2, iRegI rd ) %{
- emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, 0, $rs2$$reg );
- %}
-
- enc_class enc_to_bool( iRegI src, iRegI dst ) %{
- emit3 ( cbuf, Assembler::arith_op, 0, Assembler::subcc_op3, 0, 0, $src$$reg );
- emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::addc_op3 , 0, 0 );
- %}
-
- enc_class enc_ltmask( iRegI p, iRegI q, iRegI dst ) %{
- emit3 ( cbuf, Assembler::arith_op, 0, Assembler::subcc_op3, $p$$reg, 0, $q$$reg );
- // clear if nothing else is happening
- emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, 0 );
- // blt,a,pn done
- emit2_19 ( cbuf, Assembler::branch_op, 1/*annul*/, Assembler::less, Assembler::bp_op2, Assembler::icc, 0/*predict not taken*/, 2 );
- // mov dst,-1 in delay slot
- emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, -1 );
- %}
-
- enc_class form3_rs1_imm5_rd( iRegI rs1, immU5 imm5, iRegI rd ) %{
- emit3_simm13( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $imm5$$constant & 0x1F );
- %}
-
- enc_class form3_sd_rs1_imm6_rd( iRegL rs1, immU6 imm6, iRegL rd ) %{
- emit3_simm13( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, ($imm6$$constant & 0x3F) | 0x1000 );
- %}
-
- enc_class form3_sd_rs1_rs2_rd( iRegL rs1, iRegI rs2, iRegL rd ) %{
- emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, 0x80, $rs2$$reg );
- %}
-
- enc_class form3_rs1_simm13_rd( iRegI rs1, immI13 simm13, iRegI rd ) %{
- emit3_simm13( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $simm13$$constant );
- %}
-
- enc_class move_return_pc_to_o1() %{
- emit3_simm13( cbuf, Assembler::arith_op, R_O1_enc, Assembler::add_op3, R_O7_enc, frame::pc_return_offset );
- %}
-
- /* %%% merge with enc_to_bool */
- enc_class enc_convP2B( iRegI dst, iRegP src ) %{
- C2_MacroAssembler _masm(&cbuf);
-
- Register src_reg = reg_to_register_object($src$$reg);
- Register dst_reg = reg_to_register_object($dst$$reg);
- __ movr(Assembler::rc_nz, src_reg, 1, dst_reg);
- %}
-
- enc_class enc_cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, iRegI tmp ) %{
- // (Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)))
- C2_MacroAssembler _masm(&cbuf);
-
- Register p_reg = reg_to_register_object($p$$reg);
- Register q_reg = reg_to_register_object($q$$reg);
- Register y_reg = reg_to_register_object($y$$reg);
- Register tmp_reg = reg_to_register_object($tmp$$reg);
-
- __ subcc( p_reg, q_reg, p_reg );
- __ add ( p_reg, y_reg, tmp_reg );
- __ movcc( Assembler::less, false, Assembler::icc, tmp_reg, p_reg );
- %}
-
- enc_class form_d2i_helper(regD src, regF dst) %{
- // fcmp %fcc0,$src,$src
- emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmpd_opf, $src$$reg );
- // branch %fcc0 not-nan, predict taken
- emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 );
- // fdtoi $src,$dst
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fdtoi_opf, $src$$reg );
- // fitos $dst,$dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fitos_opf, $dst$$reg );
- // clear $dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubs_opf, $dst$$reg );
- // carry on here...
- %}
-
- enc_class form_d2l_helper(regD src, regD dst) %{
- // fcmp %fcc0,$src,$src check for NAN
- emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmpd_opf, $src$$reg );
- // branch %fcc0 not-nan, predict taken
- emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 );
- // fdtox $src,$dst convert in delay slot
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fdtox_opf, $src$$reg );
- // fxtod $dst,$dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fxtod_opf, $dst$$reg );
- // clear $dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubd_opf, $dst$$reg );
- // carry on here...
- %}
-
- enc_class form_f2i_helper(regF src, regF dst) %{
- // fcmps %fcc0,$src,$src
- emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmps_opf, $src$$reg );
- // branch %fcc0 not-nan, predict taken
- emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 );
- // fstoi $src,$dst
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fstoi_opf, $src$$reg );
- // fitos $dst,$dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fitos_opf, $dst$$reg );
- // clear $dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubs_opf, $dst$$reg );
- // carry on here...
- %}
-
- enc_class form_f2l_helper(regF src, regD dst) %{
- // fcmps %fcc0,$src,$src
- emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmps_opf, $src$$reg );
- // branch %fcc0 not-nan, predict taken
- emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 );
- // fstox $src,$dst
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fstox_opf, $src$$reg );
- // fxtod $dst,$dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fxtod_opf, $dst$$reg );
- // clear $dst (if nan)
- emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubd_opf, $dst$$reg );
- // carry on here...
- %}
-
- enc_class form3_opf_rs2F_rdF(regF rs2, regF rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %}
- enc_class form3_opf_rs2F_rdD(regF rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %}
- enc_class form3_opf_rs2D_rdF(regD rs2, regF rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %}
- enc_class form3_opf_rs2D_rdD(regD rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %}
-
- enc_class form3_opf_rs2D_lo_rdF(regD rs2, regF rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg+1); %}
-
- enc_class form3_opf_rs2D_hi_rdD_hi(regD rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %}
- enc_class form3_opf_rs2D_lo_rdD_lo(regD rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg+1,$primary,0,$tertiary,$rs2$$reg+1); %}
-
- enc_class form3_opf_rs1F_rs2F_rdF( regF rs1, regF rs2, regF rd ) %{
- emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg );
- %}
-
- enc_class form3_opf_rs1D_rs2D_rdD( regD rs1, regD rs2, regD rd ) %{
- emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg );
- %}
-
- enc_class form3_opf_rs1F_rs2F_fcc( regF rs1, regF rs2, flagsRegF fcc ) %{
- emit3( cbuf, $secondary, $fcc$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg );
- %}
-
- enc_class form3_opf_rs1D_rs2D_fcc( regD rs1, regD rs2, flagsRegF fcc ) %{
- emit3( cbuf, $secondary, $fcc$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg );
- %}
-
- enc_class form3_convI2F(regF rs2, regF rd) %{
- emit3(cbuf,Assembler::arith_op,$rd$$reg,Assembler::fpop1_op3,0,$secondary,$rs2$$reg);
- %}
-
- // Encloding class for traceable jumps
- enc_class form_jmpl(g3RegP dest) %{
- emit_jmpl(cbuf, $dest$$reg);
- %}
-
- enc_class form_jmpl_set_exception_pc(g1RegP dest) %{
- emit_jmpl_set_exception_pc(cbuf, $dest$$reg);
- %}
-
- enc_class form2_nop() %{
- emit_nop(cbuf);
- %}
-
- enc_class form2_illtrap() %{
- emit_illtrap(cbuf);
- %}
-
-
- // Compare longs and convert into -1, 0, 1.
- enc_class cmpl_flag( iRegL src1, iRegL src2, iRegI dst ) %{
- // CMP $src1,$src2
- emit3( cbuf, Assembler::arith_op, 0, Assembler::subcc_op3, $src1$$reg, 0, $src2$$reg );
- // blt,a,pn done
- emit2_19( cbuf, Assembler::branch_op, 1/*annul*/, Assembler::less , Assembler::bp_op2, Assembler::xcc, 0/*predict not taken*/, 5 );
- // mov dst,-1 in delay slot
- emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, -1 );
- // bgt,a,pn done
- emit2_19( cbuf, Assembler::branch_op, 1/*annul*/, Assembler::greater, Assembler::bp_op2, Assembler::xcc, 0/*predict not taken*/, 3 );
- // mov dst,1 in delay slot
- emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, 1 );
- // CLR $dst
- emit3( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3 , 0, 0, 0 );
- %}
-
- enc_class enc_PartialSubtypeCheck() %{
- C2_MacroAssembler _masm(&cbuf);
- __ call(StubRoutines::Sparc::partial_subtype_check(), relocInfo::runtime_call_type);
- __ delayed()->nop();
- %}
-
- enc_class enc_bp( label labl, cmpOp cmp, flagsReg cc ) %{
- C2_MacroAssembler _masm(&cbuf);
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
-
- __ bp( (Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
-
- enc_class enc_bpr( label labl, cmpOp_reg cmp, iRegI op1 ) %{
- C2_MacroAssembler _masm(&cbuf);
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
-
- __ bpr( (Assembler::RCondition)($cmp$$cmpcode), false, predict_taken, as_Register($op1$$reg), *L);
- __ delayed()->nop();
- %}
-
- enc_class enc_cmov_reg( cmpOp cmp, iRegI dst, iRegI src, immI pcc) %{
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::movcc_op3 << 19) |
- (1 << 18) | // cc2 bit for 'icc'
- ($cmp$$cmpcode << 14) |
- (0 << 13) | // select register move
- ($pcc$$constant << 11) | // cc1, cc0 bits for 'icc' or 'xcc'
- ($src$$reg << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- enc_class enc_cmov_imm( cmpOp cmp, iRegI dst, immI11 src, immI pcc ) %{
- int simm11 = $src$$constant & ((1<<11)-1); // Mask to 11 bits
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::movcc_op3 << 19) |
- (1 << 18) | // cc2 bit for 'icc'
- ($cmp$$cmpcode << 14) |
- (1 << 13) | // select immediate move
- ($pcc$$constant << 11) | // cc1, cc0 bits for 'icc'
- (simm11 << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- enc_class enc_cmov_reg_f( cmpOpF cmp, iRegI dst, iRegI src, flagsRegF fcc ) %{
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::movcc_op3 << 19) |
- (0 << 18) | // cc2 bit for 'fccX'
- ($cmp$$cmpcode << 14) |
- (0 << 13) | // select register move
- ($fcc$$reg << 11) | // cc1, cc0 bits for fcc0-fcc3
- ($src$$reg << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- enc_class enc_cmov_imm_f( cmpOp cmp, iRegI dst, immI11 src, flagsRegF fcc ) %{
- int simm11 = $src$$constant & ((1<<11)-1); // Mask to 11 bits
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::movcc_op3 << 19) |
- (0 << 18) | // cc2 bit for 'fccX'
- ($cmp$$cmpcode << 14) |
- (1 << 13) | // select immediate move
- ($fcc$$reg << 11) | // cc1, cc0 bits for fcc0-fcc3
- (simm11 << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- enc_class enc_cmovf_reg( cmpOp cmp, regD dst, regD src, immI pcc ) %{
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::fpop2_op3 << 19) |
- (0 << 18) |
- ($cmp$$cmpcode << 14) |
- (1 << 13) | // select register move
- ($pcc$$constant << 11) | // cc1-cc0 bits for 'icc' or 'xcc'
- ($primary << 5) | // select single, double or quad
- ($src$$reg << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- enc_class enc_cmovff_reg( cmpOpF cmp, flagsRegF fcc, regD dst, regD src ) %{
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::fpop2_op3 << 19) |
- (0 << 18) |
- ($cmp$$cmpcode << 14) |
- ($fcc$$reg << 11) | // cc2-cc0 bits for 'fccX'
- ($primary << 5) | // select single, double or quad
- ($src$$reg << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- // Used by the MIN/MAX encodings. Same as a CMOV, but
- // the condition comes from opcode-field instead of an argument.
- enc_class enc_cmov_reg_minmax( iRegI dst, iRegI src ) %{
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::movcc_op3 << 19) |
- (1 << 18) | // cc2 bit for 'icc'
- ($primary << 14) |
- (0 << 13) | // select register move
- (0 << 11) | // cc1, cc0 bits for 'icc'
- ($src$$reg << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- enc_class enc_cmov_reg_minmax_long( iRegL dst, iRegL src ) %{
- int op = (Assembler::arith_op << 30) |
- ($dst$$reg << 25) |
- (Assembler::movcc_op3 << 19) |
- (6 << 16) | // cc2 bit for 'xcc'
- ($primary << 14) |
- (0 << 13) | // select register move
- (0 << 11) | // cc1, cc0 bits for 'icc'
- ($src$$reg << 0);
- cbuf.insts()->emit_int32(op);
- %}
-
- enc_class Set13( immI13 src, iRegI rd ) %{
- emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, $src$$constant );
- %}
-
- enc_class SetHi22( immI src, iRegI rd ) %{
- emit2_22( cbuf, Assembler::branch_op, $rd$$reg, Assembler::sethi_op2, $src$$constant );
- %}
-
- enc_class Set32( immI src, iRegI rd ) %{
- C2_MacroAssembler _masm(&cbuf);
- __ set($src$$constant, reg_to_register_object($rd$$reg));
- %}
-
- enc_class call_epilog %{
- if( VerifyStackAtCalls ) {
- C2_MacroAssembler _masm(&cbuf);
- int framesize = ra_->C->output()->frame_size_in_bytes();
- Register temp_reg = G3;
- __ add(SP, framesize, temp_reg);
- __ cmp(temp_reg, FP);
- __ breakpoint_trap(Assembler::notEqual, Assembler::ptr_cc);
- }
- %}
-
- // Long values come back from native calls in O0:O1 in the 32-bit VM, copy the value
- // to G1 so the register allocator will not have to deal with the misaligned register
- // pair.
- enc_class adjust_long_from_native_call %{
- %}
-
- enc_class Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime
- // CALL directly to the runtime
- // The user of this is responsible for ensuring that R_L7 is empty (killed).
- emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec(), /*preserve_g2=*/true);
- %}
-
- enc_class preserve_SP %{
- C2_MacroAssembler _masm(&cbuf);
- __ mov(SP, L7_mh_SP_save);
- %}
-
- enc_class restore_SP %{
- C2_MacroAssembler _masm(&cbuf);
- __ mov(L7_mh_SP_save, SP);
- %}
-
- enc_class Java_Static_Call (method meth) %{ // JAVA STATIC CALL
- // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine
- // who we intended to call.
- if (!_method) {
- emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec());
- } else {
- int method_index = resolved_method_index(cbuf);
- RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
- : static_call_Relocation::spec(method_index);
- emit_call_reloc(cbuf, $meth$$method, rspec);
-
- // Emit stub for static call.
- address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
- if (stub == NULL) {
- ciEnv::current()->record_failure("CodeCache is full");
- return;
- }
- }
- %}
-
- enc_class Java_Dynamic_Call (method meth) %{ // JAVA DYNAMIC CALL
- C2_MacroAssembler _masm(&cbuf);
- __ set_inst_mark();
- int vtable_index = this->_vtable_index;
- // MachCallDynamicJavaNode::ret_addr_offset uses this same test
- if (vtable_index < 0) {
- // must be invalid_vtable_index, not nonvirtual_vtable_index
- assert(vtable_index == Method::invalid_vtable_index, "correct sentinel value");
- Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
- assert(G5_ic_reg == G5_inline_cache_reg, "G5_inline_cache_reg used in assemble_ic_buffer_code()");
- assert(G5_ic_reg == G5_megamorphic_method, "G5_megamorphic_method used in megamorphic call stub");
- __ ic_call((address)$meth$$method, /*emit_delay=*/true, resolved_method_index(cbuf));
- } else {
- assert(!UseInlineCaches, "expect vtable calls only if not using ICs");
- // Just go thru the vtable
- // get receiver klass (receiver already checked for non-null)
- // If we end up going thru a c2i adapter interpreter expects method in G5
- int off = __ offset();
- __ load_klass(O0, G3_scratch);
- int klass_load_size;
- if (UseCompressedClassPointers) {
- assert(Universe::heap() != NULL, "java heap should be initialized");
- klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord;
- } else {
- klass_load_size = 1*BytesPerInstWord;
- }
- int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes();
- int v_off = entry_offset + vtableEntry::method_offset_in_bytes();
- if (Assembler::is_simm13(v_off)) {
- __ ld_ptr(G3, v_off, G5_method);
- } else {
- // Generate 2 instructions
- __ Assembler::sethi(v_off & ~0x3ff, G5_method);
- __ or3(G5_method, v_off & 0x3ff, G5_method);
- // ld_ptr, set_hi, set
- assert(__ offset() - off == klass_load_size + 2*BytesPerInstWord,
- "Unexpected instruction size(s)");
- __ ld_ptr(G3, G5_method, G5_method);
- }
- // NOTE: for vtable dispatches, the vtable entry will never be null.
- // However it may very well end up in handle_wrong_method if the
- // method is abstract for the particular class.
- __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch);
- // jump to target (either compiled code or c2iadapter)
- __ jmpl(G3_scratch, G0, O7);
- __ delayed()->nop();
- }
- %}
-
- enc_class Java_Compiled_Call (method meth) %{ // JAVA COMPILED CALL
- C2_MacroAssembler _masm(&cbuf);
-
- Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
- Register temp_reg = G3; // caller must kill G3! We cannot reuse G5_ic_reg here because
- // we might be calling a C2I adapter which needs it.
-
- assert(temp_reg != G5_ic_reg, "conflicting registers");
- // Load nmethod
- __ ld_ptr(G5_ic_reg, in_bytes(Method::from_compiled_offset()), temp_reg);
-
- // CALL to compiled java, indirect the contents of G3
- __ set_inst_mark();
- __ callr(temp_reg, G0);
- __ delayed()->nop();
- %}
-
-enc_class idiv_reg(iRegIsafe src1, iRegIsafe src2, iRegIsafe dst) %{
- C2_MacroAssembler _masm(&cbuf);
- Register Rdividend = reg_to_register_object($src1$$reg);
- Register Rdivisor = reg_to_register_object($src2$$reg);
- Register Rresult = reg_to_register_object($dst$$reg);
-
- __ sra(Rdivisor, 0, Rdivisor);
- __ sra(Rdividend, 0, Rdividend);
- __ sdivx(Rdividend, Rdivisor, Rresult);
-%}
-
-enc_class idiv_imm(iRegIsafe src1, immI13 imm, iRegIsafe dst) %{
- C2_MacroAssembler _masm(&cbuf);
-
- Register Rdividend = reg_to_register_object($src1$$reg);
- int divisor = $imm$$constant;
- Register Rresult = reg_to_register_object($dst$$reg);
-
- __ sra(Rdividend, 0, Rdividend);
- __ sdivx(Rdividend, divisor, Rresult);
-%}
-
-enc_class enc_mul_hi(iRegIsafe dst, iRegIsafe src1, iRegIsafe src2) %{
- C2_MacroAssembler _masm(&cbuf);
- Register Rsrc1 = reg_to_register_object($src1$$reg);
- Register Rsrc2 = reg_to_register_object($src2$$reg);
- Register Rdst = reg_to_register_object($dst$$reg);
-
- __ sra( Rsrc1, 0, Rsrc1 );
- __ sra( Rsrc2, 0, Rsrc2 );
- __ mulx( Rsrc1, Rsrc2, Rdst );
- __ srlx( Rdst, 32, Rdst );
-%}
-
-enc_class irem_reg(iRegIsafe src1, iRegIsafe src2, iRegIsafe dst, o7RegL scratch) %{
- C2_MacroAssembler _masm(&cbuf);
- Register Rdividend = reg_to_register_object($src1$$reg);
- Register Rdivisor = reg_to_register_object($src2$$reg);
- Register Rresult = reg_to_register_object($dst$$reg);
- Register Rscratch = reg_to_register_object($scratch$$reg);
-
- assert(Rdividend != Rscratch, "");
- assert(Rdivisor != Rscratch, "");
-
- __ sra(Rdividend, 0, Rdividend);
- __ sra(Rdivisor, 0, Rdivisor);
- __ sdivx(Rdividend, Rdivisor, Rscratch);
- __ mulx(Rscratch, Rdivisor, Rscratch);
- __ sub(Rdividend, Rscratch, Rresult);
-%}
-
-enc_class irem_imm(iRegIsafe src1, immI13 imm, iRegIsafe dst, o7RegL scratch) %{
- C2_MacroAssembler _masm(&cbuf);
-
- Register Rdividend = reg_to_register_object($src1$$reg);
- int divisor = $imm$$constant;
- Register Rresult = reg_to_register_object($dst$$reg);
- Register Rscratch = reg_to_register_object($scratch$$reg);
-
- assert(Rdividend != Rscratch, "");
-
- __ sra(Rdividend, 0, Rdividend);
- __ sdivx(Rdividend, divisor, Rscratch);
- __ mulx(Rscratch, divisor, Rscratch);
- __ sub(Rdividend, Rscratch, Rresult);
-%}
-
-enc_class fabss (sflt_reg dst, sflt_reg src) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Fdst = reg_to_SingleFloatRegister_object($dst$$reg);
- FloatRegister Fsrc = reg_to_SingleFloatRegister_object($src$$reg);
-
- __ fabs(FloatRegisterImpl::S, Fsrc, Fdst);
-%}
-
-enc_class fabsd (dflt_reg dst, dflt_reg src) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg);
-
- __ fabs(FloatRegisterImpl::D, Fsrc, Fdst);
-%}
-
-enc_class fnegd (dflt_reg dst, dflt_reg src) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg);
-
- __ fneg(FloatRegisterImpl::D, Fsrc, Fdst);
-%}
-
-enc_class fsqrts (sflt_reg dst, sflt_reg src) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Fdst = reg_to_SingleFloatRegister_object($dst$$reg);
- FloatRegister Fsrc = reg_to_SingleFloatRegister_object($src$$reg);
-
- __ fsqrt(FloatRegisterImpl::S, Fsrc, Fdst);
-%}
-
-enc_class fsqrtd (dflt_reg dst, dflt_reg src) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg);
-
- __ fsqrt(FloatRegisterImpl::D, Fsrc, Fdst);
-%}
-
-
-enc_class fmadds (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg);
-
- __ fmadd(FloatRegisterImpl::S, Fra, Frb, Frc, Frd);
-%}
-
-enc_class fmaddd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg);
-
- __ fmadd(FloatRegisterImpl::D, Fra, Frb, Frc, Frd);
-%}
-
-enc_class fmsubs (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg);
-
- __ fmsub(FloatRegisterImpl::S, Fra, Frb, Frc, Frd);
-%}
-
-enc_class fmsubd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg);
-
- __ fmsub(FloatRegisterImpl::D, Fra, Frb, Frc, Frd);
-%}
-
-enc_class fnmadds (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg);
-
- __ fnmadd(FloatRegisterImpl::S, Fra, Frb, Frc, Frd);
-%}
-
-enc_class fnmaddd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg);
-
- __ fnmadd(FloatRegisterImpl::D, Fra, Frb, Frc, Frd);
-%}
-
-enc_class fnmsubs (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg);
-
- __ fnmsub(FloatRegisterImpl::S, Fra, Frb, Frc, Frd);
-%}
-
-enc_class fnmsubd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg);
- FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg);
- FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg);
-
- __ fnmsub(FloatRegisterImpl::D, Fra, Frb, Frc, Frd);
-%}
-
-
-enc_class fmovs (dflt_reg dst, dflt_reg src) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Fdst = reg_to_SingleFloatRegister_object($dst$$reg);
- FloatRegister Fsrc = reg_to_SingleFloatRegister_object($src$$reg);
-
- __ fmov(FloatRegisterImpl::S, Fsrc, Fdst);
-%}
-
-enc_class fmovd (dflt_reg dst, dflt_reg src) %{
- C2_MacroAssembler _masm(&cbuf);
-
- FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg);
- FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg);
-
- __ fmov(FloatRegisterImpl::D, Fsrc, Fdst);
-%}
-
-enc_class Fast_Lock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
- C2_MacroAssembler _masm(&cbuf);
-
- Register Roop = reg_to_register_object($oop$$reg);
- Register Rbox = reg_to_register_object($box$$reg);
- Register Rscratch = reg_to_register_object($scratch$$reg);
- Register Rmark = reg_to_register_object($scratch2$$reg);
-
- assert(Roop != Rscratch, "");
- assert(Roop != Rmark, "");
- assert(Rbox != Rscratch, "");
- assert(Rbox != Rmark, "");
-
- __ compiler_lock_object(Roop, Rmark, Rbox, Rscratch, _counters, UseBiasedLocking && !UseOptoBiasInlining);
-%}
-
-enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
- C2_MacroAssembler _masm(&cbuf);
-
- Register Roop = reg_to_register_object($oop$$reg);
- Register Rbox = reg_to_register_object($box$$reg);
- Register Rscratch = reg_to_register_object($scratch$$reg);
- Register Rmark = reg_to_register_object($scratch2$$reg);
-
- assert(Roop != Rscratch, "");
- assert(Roop != Rmark, "");
- assert(Rbox != Rscratch, "");
- assert(Rbox != Rmark, "");
-
- __ compiler_unlock_object(Roop, Rmark, Rbox, Rscratch, UseBiasedLocking && !UseOptoBiasInlining);
- %}
-
- enc_class enc_cas( iRegP mem, iRegP old, iRegP new ) %{
- C2_MacroAssembler _masm(&cbuf);
- Register Rmem = reg_to_register_object($mem$$reg);
- Register Rold = reg_to_register_object($old$$reg);
- Register Rnew = reg_to_register_object($new$$reg);
-
- __ cas_ptr(Rmem, Rold, Rnew); // Swap(*Rmem,Rnew) if *Rmem == Rold
- __ cmp( Rold, Rnew );
- %}
-
- enc_class enc_casx( iRegP mem, iRegL old, iRegL new) %{
- Register Rmem = reg_to_register_object($mem$$reg);
- Register Rold = reg_to_register_object($old$$reg);
- Register Rnew = reg_to_register_object($new$$reg);
-
- C2_MacroAssembler _masm(&cbuf);
- __ mov(Rnew, O7);
- __ casx(Rmem, Rold, O7);
- __ cmp( Rold, O7 );
- %}
-
- // raw int cas, used for compareAndSwap
- enc_class enc_casi( iRegP mem, iRegL old, iRegL new) %{
- Register Rmem = reg_to_register_object($mem$$reg);
- Register Rold = reg_to_register_object($old$$reg);
- Register Rnew = reg_to_register_object($new$$reg);
-
- C2_MacroAssembler _masm(&cbuf);
- __ mov(Rnew, O7);
- __ cas(Rmem, Rold, O7);
- __ cmp( Rold, O7 );
- %}
-
- // raw int cas without using tmp register for compareAndExchange
- enc_class enc_casi_exch( iRegP mem, iRegL old, iRegL new) %{
- Register Rmem = reg_to_register_object($mem$$reg);
- Register Rold = reg_to_register_object($old$$reg);
- Register Rnew = reg_to_register_object($new$$reg);
-
- C2_MacroAssembler _masm(&cbuf);
- __ cas(Rmem, Rold, Rnew);
- %}
-
- // 64-bit cas without using tmp register for compareAndExchange
- enc_class enc_casx_exch( iRegP mem, iRegL old, iRegL new) %{
- Register Rmem = reg_to_register_object($mem$$reg);
- Register Rold = reg_to_register_object($old$$reg);
- Register Rnew = reg_to_register_object($new$$reg);
-
- C2_MacroAssembler _masm(&cbuf);
- __ casx(Rmem, Rold, Rnew);
- %}
-
- enc_class enc_lflags_ne_to_boolean( iRegI res ) %{
- Register Rres = reg_to_register_object($res$$reg);
-
- C2_MacroAssembler _masm(&cbuf);
- __ mov(1, Rres);
- __ movcc( Assembler::notEqual, false, Assembler::xcc, G0, Rres );
- %}
-
- enc_class enc_iflags_ne_to_boolean( iRegI res ) %{
- Register Rres = reg_to_register_object($res$$reg);
-
- C2_MacroAssembler _masm(&cbuf);
- __ mov(1, Rres);
- __ movcc( Assembler::notEqual, false, Assembler::icc, G0, Rres );
- %}
-
- enc_class floating_cmp ( iRegP dst, regF src1, regF src2 ) %{
- C2_MacroAssembler _masm(&cbuf);
- Register Rdst = reg_to_register_object($dst$$reg);
- FloatRegister Fsrc1 = $primary ? reg_to_SingleFloatRegister_object($src1$$reg)
- : reg_to_DoubleFloatRegister_object($src1$$reg);
- FloatRegister Fsrc2 = $primary ? reg_to_SingleFloatRegister_object($src2$$reg)
- : reg_to_DoubleFloatRegister_object($src2$$reg);
-
- // Convert condition code fcc0 into -1,0,1; unordered reports less-than (-1)
- __ float_cmp( $primary, -1, Fsrc1, Fsrc2, Rdst);
- %}
-
- enc_class enc_rethrow() %{
- cbuf.set_insts_mark();
- Register temp_reg = G3;
- AddressLiteral rethrow_stub(OptoRuntime::rethrow_stub());
- assert(temp_reg != reg_to_register_object(R_I0_num), "temp must not break oop_reg");
- C2_MacroAssembler _masm(&cbuf);
-#ifdef ASSERT
- __ save_frame(0);
- AddressLiteral last_rethrow_addrlit(&last_rethrow);
- __ sethi(last_rethrow_addrlit, L1);
- Address addr(L1, last_rethrow_addrlit.low10());
- __ rdpc(L2);
- __ inc(L2, 3 * BytesPerInstWord); // skip this & 2 more insns to point at jump_to
- __ st_ptr(L2, addr);
- __ restore();
-#endif
- __ JUMP(rethrow_stub, temp_reg, 0); // sethi;jmp
- __ delayed()->nop();
- %}
-
- enc_class emit_mem_nop() %{
- // Generates the instruction LDUXA [o6,g0],#0x82,g0
- cbuf.insts()->emit_int32((unsigned int) 0xc0839040);
- %}
-
- enc_class emit_fadd_nop() %{
- // Generates the instruction FMOVS f31,f31
- cbuf.insts()->emit_int32((unsigned int) 0xbfa0003f);
- %}
-
- enc_class emit_br_nop() %{
- // Generates the instruction BPN,PN .
- cbuf.insts()->emit_int32((unsigned int) 0x00400000);
- %}
-
- enc_class enc_membar_acquire %{
- C2_MacroAssembler _masm(&cbuf);
- __ membar( Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::LoadLoad) );
- %}
-
- enc_class enc_membar_release %{
- C2_MacroAssembler _masm(&cbuf);
- __ membar( Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore) );
- %}
-
- enc_class enc_membar_volatile %{
- C2_MacroAssembler _masm(&cbuf);
- __ membar( Assembler::Membar_mask_bits(Assembler::StoreLoad) );
- %}
-
-%}
-
-//----------FRAME--------------------------------------------------------------
-// Definition of frame structure and management information.
-//
-// S T A C K L A Y O U T Allocators stack-slot number
-// | (to get allocators register number
-// G Owned by | | v add VMRegImpl::stack0)
-// r CALLER | |
-// o | +--------+ pad to even-align allocators stack-slot
-// w V | pad0 | numbers; owned by CALLER
-// t -----------+--------+----> Matcher::_in_arg_limit, unaligned
-// h ^ | in | 5
-// | | args | 4 Holes in incoming args owned by SELF
-// | | | | 3
-// | | +--------+
-// V | | old out| Empty on Intel, window on Sparc
-// | old |preserve| Must be even aligned.
-// | SP-+--------+----> Matcher::_old_SP, 8 (or 16 in LP64)-byte aligned
-// | | in | 3 area for Intel ret address
-// Owned by |preserve| Empty on Sparc.
-// SELF +--------+
-// | | pad2 | 2 pad to align old SP
-// | +--------+ 1
-// | | locks | 0
-// | +--------+----> VMRegImpl::stack0, 8 (or 16 in LP64)-byte aligned
-// | | pad1 | 11 pad to align new SP
-// | +--------+
-// | | | 10
-// | | spills | 9 spills
-// V | | 8 (pad0 slot for callee)
-// -----------+--------+----> Matcher::_out_arg_limit, unaligned
-// ^ | out | 7
-// | | args | 6 Holes in outgoing args owned by CALLEE
-// Owned by +--------+
-// CALLEE | new out| 6 Empty on Intel, window on Sparc
-// | new |preserve| Must be even-aligned.
-// | SP-+--------+----> Matcher::_new_SP, even aligned
-// | | |
-//
-// Note 1: Only region 8-11 is determined by the allocator. Region 0-5 is
-// known from SELF's arguments and the Java calling convention.
-// Region 6-7 is determined per call site.
-// Note 2: If the calling convention leaves holes in the incoming argument
-// area, those holes are owned by SELF. Holes in the outgoing area
-// are owned by the CALLEE. Holes should not be nessecary in the
-// incoming area, as the Java calling convention is completely under
-// the control of the AD file. Doubles can be sorted and packed to
-// avoid holes. Holes in the outgoing arguments may be necessary for
-// varargs C calling conventions.
-// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is
-// even aligned with pad0 as needed.
-// Region 6 is even aligned. Region 6-7 is NOT even aligned;
-// region 6-11 is even aligned; it may be padded out more so that
-// the region from SP to FP meets the minimum stack alignment.
-
-frame %{
- // What direction does stack grow in (assumed to be same for native & Java)
- stack_direction(TOWARDS_LOW);
-
- // These two registers define part of the calling convention
- // between compiled code and the interpreter.
- inline_cache_reg(R_G5); // Inline Cache Register or Method* for I2C
- interpreter_method_oop_reg(R_G5); // Method Oop Register when calling interpreter
-
- // Optional: name the operand used by cisc-spilling to access [stack_pointer + offset]
- cisc_spilling_operand_name(indOffset);
-
- // Number of stack slots consumed by a Monitor enter
- sync_stack_slots(2);
-
- // Compiled code's Frame Pointer
- frame_pointer(R_SP);
-
- // Stack alignment requirement
- stack_alignment(StackAlignmentInBytes);
- // LP64: Alignment size in bytes (128-bit -> 16 bytes)
- // !LP64: Alignment size in bytes (64-bit -> 8 bytes)
-
- // Number of stack slots between incoming argument block and the start of
- // a new frame. The PROLOG must add this many slots to the stack. The
- // EPILOG must remove this many slots.
- in_preserve_stack_slots(0);
-
- // Number of outgoing stack slots killed above the out_preserve_stack_slots
- // for calls to C. Supports the var-args backing area for register parms.
- // ADLC doesn't support parsing expressions, so I folded the math by hand.
- // (callee_register_argument_save_area_words (6) + callee_aggregate_return_pointer_words (0)) * 2-stack-slots-per-word
- varargs_C_out_slots_killed(12);
-
- // The after-PROLOG location of the return address. Location of
- // return address specifies a type (REG or STACK) and a number
- // representing the register number (i.e. - use a register name) or
- // stack slot.
- return_addr(REG R_I7); // Ret Addr is in register I7
-
- // Body of function which returns an OptoRegs array locating
- // arguments either in registers or in stack slots for calling
- // java
- calling_convention %{
- (void) SharedRuntime::java_calling_convention(sig_bt, regs, length, is_outgoing);
-
- %}
-
- // Body of function which returns an OptoRegs array locating
- // arguments either in registers or in stack slots for calling
- // C.
- c_calling_convention %{
- // This is obviously always outgoing
- (void) SharedRuntime::c_calling_convention(sig_bt, regs, /*regs2=*/NULL, length);
- %}
-
- // Location of native (C/C++) and interpreter return values. This is specified to
- // be the same as Java. In the 32-bit VM, long values are actually returned from
- // native calls in O0:O1 and returned to the interpreter in I0:I1. The copying
- // to and from the register pairs is done by the appropriate call and epilog
- // opcodes. This simplifies the register allocator.
- c_return_value %{
- assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" );
- static int lo_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_O0_num, R_O0_num, R_O0_num, R_F0_num, R_F0_num, R_O0_num };
- static int hi_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_O0H_num, OptoReg::Bad, R_F1_num, R_O0H_num};
- static int lo_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_I0_num, R_I0_num, R_I0_num, R_F0_num, R_F0_num, R_I0_num };
- static int hi_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_I0H_num, OptoReg::Bad, R_F1_num, R_I0H_num};
- return OptoRegPair( (is_outgoing?hi_out:hi_in)[ideal_reg],
- (is_outgoing?lo_out:lo_in)[ideal_reg] );
- %}
-
- // Location of compiled Java return values. Same as C
- return_value %{
- assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" );
- static int lo_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_O0_num, R_O0_num, R_O0_num, R_F0_num, R_F0_num, R_O0_num };
- static int hi_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_O0H_num, OptoReg::Bad, R_F1_num, R_O0H_num};
- static int lo_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_I0_num, R_I0_num, R_I0_num, R_F0_num, R_F0_num, R_I0_num };
- static int hi_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_I0H_num, OptoReg::Bad, R_F1_num, R_I0H_num};
- return OptoRegPair( (is_outgoing?hi_out:hi_in)[ideal_reg],
- (is_outgoing?lo_out:lo_in)[ideal_reg] );
- %}
-
-%}
-
-
-//----------ATTRIBUTES---------------------------------------------------------
-//----------Operand Attributes-------------------------------------------------
-op_attrib op_cost(1); // Required cost attribute
-
-//----------Instruction Attributes---------------------------------------------
-ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute
-ins_attrib ins_size(32); // Required size attribute (in bits)
-
-// avoid_back_to_back attribute is an expression that must return
-// one of the following values defined in MachNode:
-// AVOID_NONE - instruction can be placed anywhere
-// AVOID_BEFORE - instruction cannot be placed after an
-// instruction with MachNode::AVOID_AFTER
-// AVOID_AFTER - the next instruction cannot be the one
-// with MachNode::AVOID_BEFORE
-// AVOID_BEFORE_AND_AFTER - BEFORE and AFTER attributes at
-// the same time
-ins_attrib ins_avoid_back_to_back(MachNode::AVOID_NONE);
-
-ins_attrib ins_short_branch(0); // Required flag: is this instruction a
- // non-matching short branch variant of some
- // long branch?
-
-//----------OPERANDS-----------------------------------------------------------
-// Operand definitions must precede instruction definitions for correct parsing
-// in the ADLC because operands constitute user defined types which are used in
-// instruction definitions.
-
-//----------Simple Operands----------------------------------------------------
-// Immediate Operands
-// Integer Immediate: 32-bit
-operand immI() %{
- match(ConI);
-
- op_cost(0);
- // formats are generated automatically for constants and base registers
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 0-bit
-operand immI0() %{
- predicate(n->get_int() == 0);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 5-bit
-operand immI5() %{
- predicate(Assembler::is_simm5(n->get_int()));
- match(ConI);
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 8-bit
-operand immI8() %{
- predicate(Assembler::is_simm8(n->get_int()));
- match(ConI);
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: the value 10
-operand immI10() %{
- predicate(n->get_int() == 10);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 11-bit
-operand immI11() %{
- predicate(Assembler::is_simm11(n->get_int()));
- match(ConI);
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 13-bit
-operand immI13() %{
- predicate(Assembler::is_simm13(n->get_int()));
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 13-bit minus 7
-operand immI13m7() %{
- predicate((-4096 < n->get_int()) && ((n->get_int() + 7) <= 4095));
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 16-bit
-operand immI16() %{
- predicate(Assembler::is_simm16(n->get_int()));
- match(ConI);
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: the values 1-31
-operand immI_1_31() %{
- predicate(n->get_int() >= 1 && n->get_int() <= 31);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: the values 32-63
-operand immI_32_63() %{
- predicate(n->get_int() >= 32 && n->get_int() <= 63);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Immediates for special shifts (sign extend)
-
-// Integer Immediate: the value 16
-operand immI_16() %{
- predicate(n->get_int() == 16);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: the value 24
-operand immI_24() %{
- predicate(n->get_int() == 24);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-// Integer Immediate: the value 255
-operand immI_255() %{
- predicate( n->get_int() == 255 );
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: the value 65535
-operand immI_65535() %{
- predicate(n->get_int() == 65535);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: the values 0-31
-operand immU5() %{
- predicate(n->get_int() >= 0 && n->get_int() <= 31);
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 6-bit
-operand immU6() %{
- predicate(n->get_int() >= 0 && n->get_int() <= 63);
- match(ConI);
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Unsigned Integer Immediate: 12-bit (non-negative that fits in simm13)
-operand immU12() %{
- predicate((0 <= n->get_int()) && Assembler::is_simm13(n->get_int()));
- match(ConI);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Unsigned Long Immediate: 12-bit (non-negative that fits in simm13)
-operand immUL12() %{
- predicate((0 <= n->get_long()) && (n->get_long() == (int)n->get_long()) && Assembler::is_simm13((int)n->get_long()));
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate non-negative
-operand immU31()
-%{
- predicate(n->get_int() >= 0);
- match(ConI);
-
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Long Immediate: the value FF
-operand immL_FF() %{
- predicate( n->get_long() == 0xFFL );
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Long Immediate: the value FFFF
-operand immL_FFFF() %{
- predicate( n->get_long() == 0xFFFFL );
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Pointer Immediate: 32 or 64-bit
-operand immP() %{
- match(ConP);
-
- op_cost(5);
- // formats are generated automatically for constants and base registers
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Pointer Immediate: 64-bit
-operand immP_set() %{
- predicate(!VM_Version::has_fast_ld());
- match(ConP);
-
- op_cost(5);
- // formats are generated automatically for constants and base registers
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Pointer Immediate: 64-bit
-// From Niagara2 processors on a load should be better than materializing.
-operand immP_load() %{
- predicate(VM_Version::has_fast_ld() && (n->bottom_type()->isa_oop_ptr() || (MacroAssembler::insts_for_set(n->get_ptr()) > 3)));
- match(ConP);
-
- op_cost(5);
- // formats are generated automatically for constants and base registers
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Pointer Immediate: 64-bit
-operand immP_no_oop_cheap() %{
- predicate(VM_Version::has_fast_ld() && !n->bottom_type()->isa_oop_ptr() && (MacroAssembler::insts_for_set(n->get_ptr()) <= 3));
- match(ConP);
-
- op_cost(5);
- // formats are generated automatically for constants and base registers
- format %{ %}
- interface(CONST_INTER);
-%}
-
-operand immP13() %{
- predicate((-4096 < n->get_ptr()) && (n->get_ptr() <= 4095));
- match(ConP);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-operand immP0() %{
- predicate(n->get_ptr() == 0);
- match(ConP);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Pointer Immediate
-operand immN()
-%{
- match(ConN);
-
- op_cost(10);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-operand immNKlass()
-%{
- match(ConNKlass);
-
- op_cost(10);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// NULL Pointer Immediate
-operand immN0()
-%{
- predicate(n->get_narrowcon() == 0);
- match(ConN);
-
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-operand immL() %{
- match(ConL);
- op_cost(40);
- // formats are generated automatically for constants and base registers
- format %{ %}
- interface(CONST_INTER);
-%}
-
-operand immL0() %{
- predicate(n->get_long() == 0L);
- match(ConL);
- op_cost(0);
- // formats are generated automatically for constants and base registers
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Immediate: 5-bit
-operand immL5() %{
- predicate(n->get_long() == (int)n->get_long() && Assembler::is_simm5((int)n->get_long()));
- match(ConL);
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Long Immediate: 13-bit
-operand immL13() %{
- predicate((-4096L < n->get_long()) && (n->get_long() <= 4095L));
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Long Immediate: 13-bit minus 7
-operand immL13m7() %{
- predicate((-4096L < n->get_long()) && ((n->get_long() + 7L) <= 4095L));
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Long Immediate: low 32-bit mask
-operand immL_32bits() %{
- predicate(n->get_long() == 0xFFFFFFFFL);
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Long Immediate: cheap (materialize in <= 3 instructions)
-operand immL_cheap() %{
- predicate(!VM_Version::has_fast_ld() || MacroAssembler::insts_for_set64(n->get_long()) <= 3);
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Long Immediate: expensive (materialize in > 3 instructions)
-operand immL_expensive() %{
- predicate(VM_Version::has_fast_ld() && MacroAssembler::insts_for_set64(n->get_long()) > 3);
- match(ConL);
- op_cost(0);
-
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Double Immediate
-operand immD() %{
- match(ConD);
-
- op_cost(40);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Double Immediate: +0.0d
-operand immD0() %{
- predicate(jlong_cast(n->getd()) == 0);
- match(ConD);
-
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Float Immediate
-operand immF() %{
- match(ConF);
-
- op_cost(20);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Float Immediate: +0.0f
-operand immF0() %{
- predicate(jint_cast(n->getf()) == 0);
- match(ConF);
-
- op_cost(0);
- format %{ %}
- interface(CONST_INTER);
-%}
-
-// Integer Register Operands
-// Integer Register
-operand iRegI() %{
- constraint(ALLOC_IN_RC(int_reg));
- match(RegI);
-
- match(notemp_iRegI);
- match(g1RegI);
- match(o0RegI);
- match(iRegIsafe);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand notemp_iRegI() %{
- constraint(ALLOC_IN_RC(notemp_int_reg));
- match(RegI);
-
- match(o0RegI);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o0RegI() %{
- constraint(ALLOC_IN_RC(o0_regI));
- match(iRegI);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-// Pointer Register
-operand iRegP() %{
- constraint(ALLOC_IN_RC(ptr_reg));
- match(RegP);
-
- match(lock_ptr_RegP);
- match(g1RegP);
- match(g2RegP);
- match(g3RegP);
- match(g4RegP);
- match(i0RegP);
- match(o0RegP);
- match(o1RegP);
- match(l7RegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand sp_ptr_RegP() %{
- constraint(ALLOC_IN_RC(sp_ptr_reg));
- match(RegP);
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand lock_ptr_RegP() %{
- constraint(ALLOC_IN_RC(lock_ptr_reg));
- match(RegP);
- match(i0RegP);
- match(o0RegP);
- match(o1RegP);
- match(l7RegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g1RegP() %{
- constraint(ALLOC_IN_RC(g1_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g2RegP() %{
- constraint(ALLOC_IN_RC(g2_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g3RegP() %{
- constraint(ALLOC_IN_RC(g3_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g1RegI() %{
- constraint(ALLOC_IN_RC(g1_regI));
- match(iRegI);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g3RegI() %{
- constraint(ALLOC_IN_RC(g3_regI));
- match(iRegI);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g4RegI() %{
- constraint(ALLOC_IN_RC(g4_regI));
- match(iRegI);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g4RegP() %{
- constraint(ALLOC_IN_RC(g4_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand i0RegP() %{
- constraint(ALLOC_IN_RC(i0_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o0RegP() %{
- constraint(ALLOC_IN_RC(o0_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o1RegP() %{
- constraint(ALLOC_IN_RC(o1_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o2RegP() %{
- constraint(ALLOC_IN_RC(o2_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o7RegP() %{
- constraint(ALLOC_IN_RC(o7_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand l7RegP() %{
- constraint(ALLOC_IN_RC(l7_regP));
- match(iRegP);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o7RegI() %{
- constraint(ALLOC_IN_RC(o7_regI));
- match(iRegI);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand iRegN() %{
- constraint(ALLOC_IN_RC(int_reg));
- match(RegN);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-// Long Register
-operand iRegL() %{
- constraint(ALLOC_IN_RC(long_reg));
- match(RegL);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o2RegL() %{
- constraint(ALLOC_IN_RC(o2_regL));
- match(iRegL);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand o7RegL() %{
- constraint(ALLOC_IN_RC(o7_regL));
- match(iRegL);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g1RegL() %{
- constraint(ALLOC_IN_RC(g1_regL));
- match(iRegL);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand g3RegL() %{
- constraint(ALLOC_IN_RC(g3_regL));
- match(iRegL);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-// Int Register safe
-// This is 64bit safe
-operand iRegIsafe() %{
- constraint(ALLOC_IN_RC(long_reg));
-
- match(iRegI);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-// Condition Code Flag Register
-operand flagsReg() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
-
- format %{ "ccr" %} // both ICC and XCC
- interface(REG_INTER);
-%}
-
-// Condition Code Register, unsigned comparisons.
-operand flagsRegU() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
-
- format %{ "icc_U" %}
- interface(REG_INTER);
-%}
-
-// Condition Code Register, pointer comparisons.
-operand flagsRegP() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
-
- format %{ "xcc_P" %}
- interface(REG_INTER);
-%}
-
-// Condition Code Register, long comparisons.
-operand flagsRegL() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
-
- format %{ "xcc_L" %}
- interface(REG_INTER);
-%}
-
-// Condition Code Register, unsigned long comparisons.
-operand flagsRegUL() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
-
- format %{ "xcc_UL" %}
- interface(REG_INTER);
-%}
-
-// Condition Code Register, floating comparisons, unordered same as "less".
-operand flagsRegF() %{
- constraint(ALLOC_IN_RC(float_flags));
- match(RegFlags);
- match(flagsRegF0);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand flagsRegF0() %{
- constraint(ALLOC_IN_RC(float_flag0));
- match(RegFlags);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-
-// Condition Code Flag Register used by long compare
-operand flagsReg_long_LTGE() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
- format %{ "icc_LTGE" %}
- interface(REG_INTER);
-%}
-operand flagsReg_long_EQNE() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
- format %{ "icc_EQNE" %}
- interface(REG_INTER);
-%}
-operand flagsReg_long_LEGT() %{
- constraint(ALLOC_IN_RC(int_flags));
- match(RegFlags);
- format %{ "icc_LEGT" %}
- interface(REG_INTER);
-%}
-
-
-operand regD() %{
- constraint(ALLOC_IN_RC(dflt_reg));
- match(RegD);
-
- match(regD_low);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand regF() %{
- constraint(ALLOC_IN_RC(sflt_reg));
- match(RegF);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand regD_low() %{
- constraint(ALLOC_IN_RC(dflt_low_reg));
- match(regD);
-
- format %{ %}
- interface(REG_INTER);
-%}
-
-// Special Registers
-
-// Method Register
-operand inline_cache_regP(iRegP reg) %{
- constraint(ALLOC_IN_RC(g5_regP)); // G5=inline_cache_reg but uses 2 bits instead of 1
- match(reg);
- format %{ %}
- interface(REG_INTER);
-%}
-
-operand interpreter_method_oop_regP(iRegP reg) %{
- constraint(ALLOC_IN_RC(g5_regP)); // G5=interpreter_method_oop_reg but uses 2 bits instead of 1
- match(reg);
- format %{ %}
- interface(REG_INTER);
-%}
-
-
-//----------Complex Operands---------------------------------------------------
-// Indirect Memory Reference
-operand indirect(sp_ptr_RegP reg) %{
- constraint(ALLOC_IN_RC(sp_ptr_reg));
- match(reg);
-
- op_cost(100);
- format %{ "[$reg]" %}
- interface(MEMORY_INTER) %{
- base($reg);
- index(0x0);
- scale(0x0);
- disp(0x0);
- %}
-%}
-
-// Indirect with simm13 Offset
-operand indOffset13(sp_ptr_RegP reg, immX13 offset) %{
- constraint(ALLOC_IN_RC(sp_ptr_reg));
- match(AddP reg offset);
-
- op_cost(100);
- format %{ "[$reg + $offset]" %}
- interface(MEMORY_INTER) %{
- base($reg);
- index(0x0);
- scale(0x0);
- disp($offset);
- %}
-%}
-
-// Indirect with simm13 Offset minus 7
-operand indOffset13m7(sp_ptr_RegP reg, immX13m7 offset) %{
- constraint(ALLOC_IN_RC(sp_ptr_reg));
- match(AddP reg offset);
-
- op_cost(100);
- format %{ "[$reg + $offset]" %}
- interface(MEMORY_INTER) %{
- base($reg);
- index(0x0);
- scale(0x0);
- disp($offset);
- %}
-%}
-
-// Note: Intel has a swapped version also, like this:
-//operand indOffsetX(iRegI reg, immP offset) %{
-// constraint(ALLOC_IN_RC(int_reg));
-// match(AddP offset reg);
-//
-// op_cost(100);
-// format %{ "[$reg + $offset]" %}
-// interface(MEMORY_INTER) %{
-// base($reg);
-// index(0x0);
-// scale(0x0);
-// disp($offset);
-// %}
-//%}
-//// However, it doesn't make sense for SPARC, since
-// we have no particularly good way to embed oops in
-// single instructions.
-
-// Indirect with Register Index
-operand indIndex(iRegP addr, iRegX index) %{
- constraint(ALLOC_IN_RC(ptr_reg));
- match(AddP addr index);
-
- op_cost(100);
- format %{ "[$addr + $index]" %}
- interface(MEMORY_INTER) %{
- base($addr);
- index($index);
- scale(0x0);
- disp(0x0);
- %}
-%}
-
-//----------Special Memory Operands--------------------------------------------
-// Stack Slot Operand - This operand is used for loading and storing temporary
-// values on the stack where a match requires a value to
-// flow through memory.
-operand stackSlotI(sRegI reg) %{
- constraint(ALLOC_IN_RC(stack_slots));
- op_cost(100);
- //match(RegI);
- format %{ "[$reg]" %}
- interface(MEMORY_INTER) %{
- base(0xE); // R_SP
- index(0x0);
- scale(0x0);
- disp($reg); // Stack Offset
- %}
-%}
-
-operand stackSlotP(sRegP reg) %{
- constraint(ALLOC_IN_RC(stack_slots));
- op_cost(100);
- //match(RegP);
- format %{ "[$reg]" %}
- interface(MEMORY_INTER) %{
- base(0xE); // R_SP
- index(0x0);
- scale(0x0);
- disp($reg); // Stack Offset
- %}
-%}
-
-operand stackSlotF(sRegF reg) %{
- constraint(ALLOC_IN_RC(stack_slots));
- op_cost(100);
- //match(RegF);
- format %{ "[$reg]" %}
- interface(MEMORY_INTER) %{
- base(0xE); // R_SP
- index(0x0);
- scale(0x0);
- disp($reg); // Stack Offset
- %}
-%}
-operand stackSlotD(sRegD reg) %{
- constraint(ALLOC_IN_RC(stack_slots));
- op_cost(100);
- //match(RegD);
- format %{ "[$reg]" %}
- interface(MEMORY_INTER) %{
- base(0xE); // R_SP
- index(0x0);
- scale(0x0);
- disp($reg); // Stack Offset
- %}
-%}
-operand stackSlotL(sRegL reg) %{
- constraint(ALLOC_IN_RC(stack_slots));
- op_cost(100);
- //match(RegL);
- format %{ "[$reg]" %}
- interface(MEMORY_INTER) %{
- base(0xE); // R_SP
- index(0x0);
- scale(0x0);
- disp($reg); // Stack Offset
- %}
-%}
-
-// Operands for expressing Control Flow
-// NOTE: Label is a predefined operand which should not be redefined in
-// the AD file. It is generically handled within the ADLC.
-
-//----------Conditional Branch Operands----------------------------------------
-// Comparison Op - This is the operation of the comparison, and is limited to
-// the following set of codes:
-// L (<), LE (<=), G (>), GE (>=), E (==), NE (!=)
-//
-// Other attributes of the comparison, such as unsignedness, are specified
-// by the comparison instruction that sets a condition code flags register.
-// That result is represented by a flags operand whose subtype is appropriate
-// to the unsignedness (etc.) of the comparison.
-//
-// Later, the instruction which matches both the Comparison Op (a Bool) and
-// the flags (produced by the Cmp) specifies the coding of the comparison op
-// by matching a specific subtype of Bool operand below, such as cmpOpU.
-
-operand cmpOp() %{
- match(Bool);
-
- format %{ "" %}
- interface(COND_INTER) %{
- equal(0x1);
- not_equal(0x9);
- less(0x3);
- greater_equal(0xB);
- less_equal(0x2);
- greater(0xA);
- overflow(0x7);
- no_overflow(0xF);
- %}
-%}
-
-// Comparison Op, unsigned
-operand cmpOpU() %{
- match(Bool);
- predicate(n->as_Bool()->_test._test != BoolTest::overflow &&
- n->as_Bool()->_test._test != BoolTest::no_overflow);
-
- format %{ "u" %}
- interface(COND_INTER) %{
- equal(0x1);
- not_equal(0x9);
- less(0x5);
- greater_equal(0xD);
- less_equal(0x4);
- greater(0xC);
- overflow(0x7);
- no_overflow(0xF);
- %}
-%}
-
-// Comparison Op, pointer (same as unsigned)
-operand cmpOpP() %{
- match(Bool);
- predicate(n->as_Bool()->_test._test != BoolTest::overflow &&
- n->as_Bool()->_test._test != BoolTest::no_overflow);
-
- format %{ "p" %}
- interface(COND_INTER) %{
- equal(0x1);
- not_equal(0x9);
- less(0x5);
- greater_equal(0xD);
- less_equal(0x4);
- greater(0xC);
- overflow(0x7);
- no_overflow(0xF);
- %}
-%}
-
-// Comparison Op, branch-register encoding
-operand cmpOp_reg() %{
- match(Bool);
- predicate(n->as_Bool()->_test._test != BoolTest::overflow &&
- n->as_Bool()->_test._test != BoolTest::no_overflow);
-
- format %{ "" %}
- interface(COND_INTER) %{
- equal (0x1);
- not_equal (0x5);
- less (0x3);
- greater_equal(0x7);
- less_equal (0x2);
- greater (0x6);
- overflow(0x7); // not supported
- no_overflow(0xF); // not supported
- %}
-%}
-
-// Comparison Code, floating, unordered same as less
-operand cmpOpF() %{
- match(Bool);
- predicate(n->as_Bool()->_test._test != BoolTest::overflow &&
- n->as_Bool()->_test._test != BoolTest::no_overflow);
-
- format %{ "fl" %}
- interface(COND_INTER) %{
- equal(0x9);
- not_equal(0x1);
- less(0x3);
- greater_equal(0xB);
- less_equal(0xE);
- greater(0x6);
-
- overflow(0x7); // not supported
- no_overflow(0xF); // not supported
- %}
-%}
-
-// Used by long compare
-operand cmpOp_commute() %{
- match(Bool);
- predicate(n->as_Bool()->_test._test != BoolTest::overflow &&
- n->as_Bool()->_test._test != BoolTest::no_overflow);
-
- format %{ "" %}
- interface(COND_INTER) %{
- equal(0x1);
- not_equal(0x9);
- less(0xA);
- greater_equal(0x2);
- less_equal(0xB);
- greater(0x3);
- overflow(0x7);
- no_overflow(0xF);
- %}
-%}
-
-//----------OPERAND CLASSES----------------------------------------------------
-// Operand Classes are groups of operands that are used to simplify
-// instruction definitions by not requiring the AD writer to specify separate
-// instructions for every form of operand when the instruction accepts
-// multiple operand types with the same basic encoding and format. The classic
-// case of this is memory operands.
-opclass memory( indirect, indOffset13, indIndex );
-opclass indIndexMemory( indIndex );
-
-//----------PIPELINE-----------------------------------------------------------
-pipeline %{
-
-//----------ATTRIBUTES---------------------------------------------------------
-attributes %{
- fixed_size_instructions; // Fixed size instructions
- branch_has_delay_slot; // Branch has delay slot following
- max_instructions_per_bundle = 4; // Up to 4 instructions per bundle
- instruction_unit_size = 4; // An instruction is 4 bytes long
- instruction_fetch_unit_size = 16; // The processor fetches one line
- instruction_fetch_units = 1; // of 16 bytes
-
- // List of nop instructions
- nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR );
-%}
-
-//----------RESOURCES----------------------------------------------------------
-// Resources are the functional units available to the machine
-resources(A0, A1, MS, BR, FA, FM, IDIV, FDIV, IALU = A0 | A1);
-
-//----------PIPELINE DESCRIPTION-----------------------------------------------
-// Pipeline Description specifies the stages in the machine's pipeline
-
-pipe_desc(A, P, F, B, I, J, S, R, E, C, M, W, X, T, D);
-
-//----------PIPELINE CLASSES---------------------------------------------------
-// Pipeline Classes describe the stages in which input and output are
-// referenced by the hardware pipeline.
-
-// Integer ALU reg-reg operation
-pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- single_instruction;
- dst : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-reg long operation
-pipe_class ialu_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{
- instruction_count(2);
- dst : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
- IALU : R;
-%}
-
-// Integer ALU reg-reg long dependent operation
-pipe_class ialu_reg_reg_2_dep(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{
- instruction_count(1); multiple_bundles;
- dst : E(write);
- src1 : R(read);
- src2 : R(read);
- cr : E(write);
- IALU : R(2);
-%}
-
-// Integer ALU reg-imm operaion
-pipe_class ialu_reg_imm(iRegI dst, iRegI src1, immI13 src2) %{
- single_instruction;
- dst : E(write);
- src1 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-reg operation with condition code
-pipe_class ialu_cc_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
- single_instruction;
- dst : E(write);
- cr : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-imm operation with condition code
-pipe_class ialu_cc_reg_imm(iRegI dst, iRegI src1, immI13 src2, flagsReg cr) %{
- single_instruction;
- dst : E(write);
- cr : E(write);
- src1 : R(read);
- IALU : R;
-%}
-
-// Integer ALU zero-reg operation
-pipe_class ialu_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{
- single_instruction;
- dst : E(write);
- src2 : R(read);
- IALU : R;
-%}
-
-// Integer ALU zero-reg operation with condition code only
-pipe_class ialu_cconly_zero_reg(flagsReg cr, iRegI src) %{
- single_instruction;
- cr : E(write);
- src : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-reg operation with condition code only
-pipe_class ialu_cconly_reg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
- single_instruction;
- cr : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-imm operation with condition code only
-pipe_class ialu_cconly_reg_imm(flagsReg cr, iRegI src1, immI13 src2) %{
- single_instruction;
- cr : E(write);
- src1 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-reg-zero operation with condition code only
-pipe_class ialu_cconly_reg_reg_zero(flagsReg cr, iRegI src1, iRegI src2, immI0 zero) %{
- single_instruction;
- cr : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-imm-zero operation with condition code only
-pipe_class ialu_cconly_reg_imm_zero(flagsReg cr, iRegI src1, immI13 src2, immI0 zero) %{
- single_instruction;
- cr : E(write);
- src1 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-reg operation with condition code, src1 modified
-pipe_class ialu_cc_rwreg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
- single_instruction;
- cr : E(write);
- src1 : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg-imm operation with condition code, src1 modified
-pipe_class ialu_cc_rwreg_imm(flagsReg cr, iRegI src1, immI13 src2) %{
- single_instruction;
- cr : E(write);
- src1 : E(write);
- src1 : R(read);
- IALU : R;
-%}
-
-pipe_class cmpL_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg cr ) %{
- multiple_bundles;
- dst : E(write)+4;
- cr : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R(3);
- BR : R(2);
-%}
-
-// Integer ALU operation
-pipe_class ialu_none(iRegI dst) %{
- single_instruction;
- dst : E(write);
- IALU : R;
-%}
-
-// Integer ALU reg operation
-pipe_class ialu_reg(iRegI dst, iRegI src) %{
- single_instruction; may_have_no_code;
- dst : E(write);
- src : R(read);
- IALU : R;
-%}
-
-// Integer ALU reg conditional operation
-// This instruction has a 1 cycle stall, and cannot execute
-// in the same cycle as the instruction setting the condition
-// code. We kludge this by pretending to read the condition code
-// 1 cycle earlier, and by marking the functional units as busy
-// for 2 cycles with the result available 1 cycle later than
-// is really the case.
-pipe_class ialu_reg_flags( iRegI op2_out, iRegI op2_in, iRegI op1, flagsReg cr ) %{
- single_instruction;
- op2_out : C(write);
- op1 : R(read);
- cr : R(read); // This is really E, with a 1 cycle stall
- BR : R(2);
- MS : R(2);
-%}
-
-pipe_class ialu_clr_and_mover( iRegI dst, iRegP src ) %{
- instruction_count(1); multiple_bundles;
- dst : C(write)+1;
- src : R(read)+1;
- IALU : R(1);
- BR : E(2);
- MS : E(2);
-%}
-
-// Integer ALU reg operation
-pipe_class ialu_move_reg_L_to_I(iRegI dst, iRegL src) %{
- single_instruction; may_have_no_code;
- dst : E(write);
- src : R(read);
- IALU : R;
-%}
-pipe_class ialu_move_reg_I_to_L(iRegL dst, iRegI src) %{
- single_instruction; may_have_no_code;
- dst : E(write);
- src : R(read);
- IALU : R;
-%}
-
-// Two integer ALU reg operations
-pipe_class ialu_reg_2(iRegL dst, iRegL src) %{
- instruction_count(2);
- dst : E(write);
- src : R(read);
- A0 : R;
- A1 : R;
-%}
-
-// Two integer ALU reg operations
-pipe_class ialu_move_reg_L_to_L(iRegL dst, iRegL src) %{
- instruction_count(2); may_have_no_code;
- dst : E(write);
- src : R(read);
- A0 : R;
- A1 : R;
-%}
-
-// Integer ALU imm operation
-pipe_class ialu_imm(iRegI dst, immI13 src) %{
- single_instruction;
- dst : E(write);
- IALU : R;
-%}
-
-// Integer ALU reg-reg with carry operation
-pipe_class ialu_reg_reg_cy(iRegI dst, iRegI src1, iRegI src2, iRegI cy) %{
- single_instruction;
- dst : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
-%}
-
-// Integer ALU cc operation
-pipe_class ialu_cc(iRegI dst, flagsReg cc) %{
- single_instruction;
- dst : E(write);
- cc : R(read);
- IALU : R;
-%}
-
-// Integer ALU cc / second IALU operation
-pipe_class ialu_reg_ialu( iRegI dst, iRegI src ) %{
- instruction_count(1); multiple_bundles;
- dst : E(write)+1;
- src : R(read);
- IALU : R;
-%}
-
-// Integer ALU cc / second IALU operation
-pipe_class ialu_reg_reg_ialu( iRegI dst, iRegI p, iRegI q ) %{
- instruction_count(1); multiple_bundles;
- dst : E(write)+1;
- p : R(read);
- q : R(read);
- IALU : R;
-%}
-
-// Integer ALU hi-lo-reg operation
-pipe_class ialu_hi_lo_reg(iRegI dst, immI src) %{
- instruction_count(1); multiple_bundles;
- dst : E(write)+1;
- IALU : R(2);
-%}
-
-// Float ALU hi-lo-reg operation (with temp)
-pipe_class ialu_hi_lo_reg_temp(regF dst, immF src, g3RegP tmp) %{
- instruction_count(1); multiple_bundles;
- dst : E(write)+1;
- IALU : R(2);
-%}
-
-// Long Constant
-pipe_class loadConL( iRegL dst, immL src ) %{
- instruction_count(2); multiple_bundles;
- dst : E(write)+1;
- IALU : R(2);
- IALU : R(2);
-%}
-
-// Pointer Constant
-pipe_class loadConP( iRegP dst, immP src ) %{
- instruction_count(0); multiple_bundles;
- fixed_latency(6);
-%}
-
-// Long Constant small
-pipe_class loadConLlo( iRegL dst, immL src ) %{
- instruction_count(2);
- dst : E(write);
- IALU : R;
- IALU : R;
-%}
-
-// [PHH] This is wrong for 64-bit. See LdImmF/D.
-pipe_class loadConFD(regF dst, immF src, g3RegP tmp) %{
- instruction_count(1); multiple_bundles;
- src : R(read);
- dst : M(write)+1;
- IALU : R;
- MS : E;
-%}
-
-// Integer ALU nop operation
-pipe_class ialu_nop() %{
- single_instruction;
- IALU : R;
-%}
-
-// Integer ALU nop operation
-pipe_class ialu_nop_A0() %{
- single_instruction;
- A0 : R;
-%}
-
-// Integer ALU nop operation
-pipe_class ialu_nop_A1() %{
- single_instruction;
- A1 : R;
-%}
-
-// Integer Multiply reg-reg operation
-pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- single_instruction;
- dst : E(write);
- src1 : R(read);
- src2 : R(read);
- MS : R(5);
-%}
-
-// Integer Multiply reg-imm operation
-pipe_class imul_reg_imm(iRegI dst, iRegI src1, immI13 src2) %{
- single_instruction;
- dst : E(write);
- src1 : R(read);
- MS : R(5);
-%}
-
-pipe_class mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- single_instruction;
- dst : E(write)+4;
- src1 : R(read);
- src2 : R(read);
- MS : R(6);
-%}
-
-pipe_class mulL_reg_imm(iRegL dst, iRegL src1, immL13 src2) %{
- single_instruction;
- dst : E(write)+4;
- src1 : R(read);
- MS : R(6);
-%}
-
-// Integer Divide reg-reg
-pipe_class sdiv_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI temp, flagsReg cr) %{
- instruction_count(1); multiple_bundles;
- dst : E(write);
- temp : E(write);
- src1 : R(read);
- src2 : R(read);
- temp : R(read);
- MS : R(38);
-%}
-
-// Integer Divide reg-imm
-pipe_class sdiv_reg_imm(iRegI dst, iRegI src1, immI13 src2, iRegI temp, flagsReg cr) %{
- instruction_count(1); multiple_bundles;
- dst : E(write);
- temp : E(write);
- src1 : R(read);
- temp : R(read);
- MS : R(38);
-%}
-
-// Long Divide
-pipe_class divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- dst : E(write)+71;
- src1 : R(read);
- src2 : R(read)+1;
- MS : R(70);
-%}
-
-pipe_class divL_reg_imm(iRegL dst, iRegL src1, immL13 src2) %{
- dst : E(write)+71;
- src1 : R(read);
- MS : R(70);
-%}
-
-// Floating Point Add Float
-pipe_class faddF_reg_reg(regF dst, regF src1, regF src2) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- FA : R;
-%}
-
-// Floating Point Add Double
-pipe_class faddD_reg_reg(regD dst, regD src1, regD src2) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- FA : R;
-%}
-
-// Floating Point Conditional Move based on integer flags
-pipe_class int_conditional_float_move (cmpOp cmp, flagsReg cr, regF dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- cr : R(read);
- FA : R(2);
- BR : R(2);
-%}
-
-// Floating Point Conditional Move based on integer flags
-pipe_class int_conditional_double_move (cmpOp cmp, flagsReg cr, regD dst, regD src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- cr : R(read);
- FA : R(2);
- BR : R(2);
-%}
-
-// Floating Point Multiply Float
-pipe_class fmulF_reg_reg(regF dst, regF src1, regF src2) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- FM : R;
-%}
-
-// Floating Point Multiply Double
-pipe_class fmulD_reg_reg(regD dst, regD src1, regD src2) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- FM : R;
-%}
-
-// Floating Point Divide Float
-pipe_class fdivF_reg_reg(regF dst, regF src1, regF src2) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- FM : R;
- FDIV : C(14);
-%}
-
-// Floating Point Divide Double
-pipe_class fdivD_reg_reg(regD dst, regD src1, regD src2) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- FM : R;
- FDIV : C(17);
-%}
-
-// Fused floating-point multiply-add float.
-pipe_class fmaF_regx4(regF dst, regF src1, regF src2, regF src3) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- src3 : E(read);
- FM : R;
-%}
-
-// Fused gloating-point multiply-add double.
-pipe_class fmaD_regx4(regD dst, regD src1, regD src2, regD src3) %{
- single_instruction;
- dst : X(write);
- src1 : E(read);
- src2 : E(read);
- src3 : E(read);
- FM : R;
-%}
-
-// Floating Point Move/Negate/Abs Float
-pipe_class faddF_reg(regF dst, regF src) %{
- single_instruction;
- dst : W(write);
- src : E(read);
- FA : R(1);
-%}
-
-// Floating Point Move/Negate/Abs Double
-pipe_class faddD_reg(regD dst, regD src) %{
- single_instruction;
- dst : W(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert F->D
-pipe_class fcvtF2D(regD dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert I->D
-pipe_class fcvtI2D(regD dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert LHi->D
-pipe_class fcvtLHi2D(regD dst, regD src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert L->D
-pipe_class fcvtL2D(regD dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert L->F
-pipe_class fcvtL2F(regD dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert D->F
-pipe_class fcvtD2F(regD dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert I->L
-pipe_class fcvtI2L(regD dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert D->F
-pipe_class fcvtD2I(regF dst, regD src, flagsReg cr) %{
- instruction_count(1); multiple_bundles;
- dst : X(write)+6;
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert D->L
-pipe_class fcvtD2L(regD dst, regD src, flagsReg cr) %{
- instruction_count(1); multiple_bundles;
- dst : X(write)+6;
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert F->I
-pipe_class fcvtF2I(regF dst, regF src, flagsReg cr) %{
- instruction_count(1); multiple_bundles;
- dst : X(write)+6;
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert F->L
-pipe_class fcvtF2L(regD dst, regF src, flagsReg cr) %{
- instruction_count(1); multiple_bundles;
- dst : X(write)+6;
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Convert I->F
-pipe_class fcvtI2F(regF dst, regF src) %{
- single_instruction;
- dst : X(write);
- src : E(read);
- FA : R;
-%}
-
-// Floating Point Compare
-pipe_class faddF_fcc_reg_reg_zero(flagsRegF cr, regF src1, regF src2, immI0 zero) %{
- single_instruction;
- cr : X(write);
- src1 : E(read);
- src2 : E(read);
- FA : R;
-%}
-
-// Floating Point Compare
-pipe_class faddD_fcc_reg_reg_zero(flagsRegF cr, regD src1, regD src2, immI0 zero) %{
- single_instruction;
- cr : X(write);
- src1 : E(read);
- src2 : E(read);
- FA : R;
-%}
-
-// Floating Add Nop
-pipe_class fadd_nop() %{
- single_instruction;
- FA : R;
-%}
-
-// Integer Store to Memory
-pipe_class istore_mem_reg(memory mem, iRegI src) %{
- single_instruction;
- mem : R(read);
- src : C(read);
- MS : R;
-%}
-
-// Integer Store to Memory
-pipe_class istore_mem_spORreg(memory mem, sp_ptr_RegP src) %{
- single_instruction;
- mem : R(read);
- src : C(read);
- MS : R;
-%}
-
-// Integer Store Zero to Memory
-pipe_class istore_mem_zero(memory mem, immI0 src) %{
- single_instruction;
- mem : R(read);
- MS : R;
-%}
-
-// Special Stack Slot Store
-pipe_class istore_stk_reg(stackSlotI stkSlot, iRegI src) %{
- single_instruction;
- stkSlot : R(read);
- src : C(read);
- MS : R;
-%}
-
-// Special Stack Slot Store
-pipe_class lstoreI_stk_reg(stackSlotL stkSlot, iRegI src) %{
- instruction_count(2); multiple_bundles;
- stkSlot : R(read);
- src : C(read);
- MS : R(2);
-%}
-
-// Float Store
-pipe_class fstoreF_mem_reg(memory mem, RegF src) %{
- single_instruction;
- mem : R(read);
- src : C(read);
- MS : R;
-%}
-
-// Float Store
-pipe_class fstoreF_mem_zero(memory mem, immF0 src) %{
- single_instruction;
- mem : R(read);
- MS : R;
-%}
-
-// Double Store
-pipe_class fstoreD_mem_reg(memory mem, RegD src) %{
- instruction_count(1);
- mem : R(read);
- src : C(read);
- MS : R;
-%}
-
-// Double Store
-pipe_class fstoreD_mem_zero(memory mem, immD0 src) %{
- single_instruction;
- mem : R(read);
- MS : R;
-%}
-
-// Special Stack Slot Float Store
-pipe_class fstoreF_stk_reg(stackSlotI stkSlot, RegF src) %{
- single_instruction;
- stkSlot : R(read);
- src : C(read);
- MS : R;
-%}
-
-// Special Stack Slot Double Store
-pipe_class fstoreD_stk_reg(stackSlotI stkSlot, RegD src) %{
- single_instruction;
- stkSlot : R(read);
- src : C(read);
- MS : R;
-%}
-
-// Integer Load (when sign bit propagation not needed)
-pipe_class iload_mem(iRegI dst, memory mem) %{
- single_instruction;
- mem : R(read);
- dst : C(write);
- MS : R;
-%}
-
-// Integer Load from stack operand
-pipe_class iload_stkD(iRegI dst, stackSlotD mem ) %{
- single_instruction;
- mem : R(read);
- dst : C(write);
- MS : R;
-%}
-
-// Integer Load (when sign bit propagation or masking is needed)
-pipe_class iload_mask_mem(iRegI dst, memory mem) %{
- single_instruction;
- mem : R(read);
- dst : M(write);
- MS : R;
-%}
-
-// Float Load
-pipe_class floadF_mem(regF dst, memory mem) %{
- single_instruction;
- mem : R(read);
- dst : M(write);
- MS : R;
-%}
-
-// Float Load
-pipe_class floadD_mem(regD dst, memory mem) %{
- instruction_count(1); multiple_bundles; // Again, unaligned argument is only multiple case
- mem : R(read);
- dst : M(write);
- MS : R;
-%}
-
-// Float Load
-pipe_class floadF_stk(regF dst, stackSlotI stkSlot) %{
- single_instruction;
- stkSlot : R(read);
- dst : M(write);
- MS : R;
-%}
-
-// Float Load
-pipe_class floadD_stk(regD dst, stackSlotI stkSlot) %{
- single_instruction;
- stkSlot : R(read);
- dst : M(write);
- MS : R;
-%}
-
-// Memory Nop
-pipe_class mem_nop() %{
- single_instruction;
- MS : R;
-%}
-
-pipe_class sethi(iRegP dst, immI src) %{
- single_instruction;
- dst : E(write);
- IALU : R;
-%}
-
-pipe_class loadPollP(iRegP poll) %{
- single_instruction;
- poll : R(read);
- MS : R;
-%}
-
-pipe_class br(Universe br, label labl) %{
- single_instruction_with_delay_slot;
- BR : R;
-%}
-
-pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{
- single_instruction_with_delay_slot;
- cr : E(read);
- BR : R;
-%}
-
-pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{
- single_instruction_with_delay_slot;
- op1 : E(read);
- BR : R;
- MS : R;
-%}
-
-// Compare and branch
-pipe_class cmp_br_reg_reg(Universe br, cmpOp cmp, iRegI src1, iRegI src2, label labl, flagsReg cr) %{
- instruction_count(2); has_delay_slot;
- cr : E(write);
- src1 : R(read);
- src2 : R(read);
- IALU : R;
- BR : R;
-%}
-
-// Compare and branch
-pipe_class cmp_br_reg_imm(Universe br, cmpOp cmp, iRegI src1, immI13 src2, label labl, flagsReg cr) %{
- instruction_count(2); has_delay_slot;
- cr : E(write);
- src1 : R(read);
- IALU : R;
- BR : R;
-%}
-
-// Compare and branch using cbcond
-pipe_class cbcond_reg_reg(Universe br, cmpOp cmp, iRegI src1, iRegI src2, label labl) %{
- single_instruction;
- src1 : E(read);
- src2 : E(read);
- IALU : R;
- BR : R;
-%}
-
-// Compare and branch using cbcond
-pipe_class cbcond_reg_imm(Universe br, cmpOp cmp, iRegI src1, immI5 src2, label labl) %{
- single_instruction;
- src1 : E(read);
- IALU : R;
- BR : R;
-%}
-
-pipe_class br_fcc(Universe br, cmpOpF cc, flagsReg cr, label labl) %{
- single_instruction_with_delay_slot;
- cr : E(read);
- BR : R;
-%}
-
-pipe_class br_nop() %{
- single_instruction;
- BR : R;
-%}
-
-pipe_class simple_call(method meth) %{
- instruction_count(2); multiple_bundles; force_serialization;
- fixed_latency(100);
- BR : R(1);
- MS : R(1);
- A0 : R(1);
-%}
-
-pipe_class compiled_call(method meth) %{
- instruction_count(1); multiple_bundles; force_serialization;
- fixed_latency(100);
- MS : R(1);
-%}
-
-pipe_class call(method meth) %{
- instruction_count(0); multiple_bundles; force_serialization;
- fixed_latency(100);
-%}
-
-pipe_class tail_call(Universe ignore, label labl) %{
- single_instruction; has_delay_slot;
- fixed_latency(100);
- BR : R(1);
- MS : R(1);
-%}
-
-pipe_class ret(Universe ignore) %{
- single_instruction; has_delay_slot;
- BR : R(1);
- MS : R(1);
-%}
-
-pipe_class ret_poll(g3RegP poll) %{
- instruction_count(3); has_delay_slot;
- poll : E(read);
- MS : R;
-%}
-
-// The real do-nothing guy
-pipe_class empty( ) %{
- instruction_count(0);
-%}
-
-pipe_class long_memory_op() %{
- instruction_count(0); multiple_bundles; force_serialization;
- fixed_latency(25);
- MS : R(1);
-%}
-
-// Check-cast
-pipe_class partial_subtype_check_pipe(Universe ignore, iRegP array, iRegP match ) %{
- array : R(read);
- match : R(read);
- IALU : R(2);
- BR : R(2);
- MS : R;
-%}
-
-// Convert FPU flags into +1,0,-1
-pipe_class floating_cmp( iRegI dst, regF src1, regF src2 ) %{
- src1 : E(read);
- src2 : E(read);
- dst : E(write);
- FA : R;
- MS : R(2);
- BR : R(2);
-%}
-
-// Compare for p < q, and conditionally add y
-pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{
- p : E(read);
- q : E(read);
- y : E(read);
- IALU : R(3)
-%}
-
-// Perform a compare, then move conditionally in a branch delay slot.
-pipe_class min_max( iRegI src2, iRegI srcdst ) %{
- src2 : E(read);
- srcdst : E(read);
- IALU : R;
- BR : R;
-%}
-
-// Define the class for the Nop node
-define %{
- MachNop = ialu_nop;
-%}
-
-%}
-
-//----------INSTRUCTIONS-------------------------------------------------------
-
-//------------Special Stack Slot instructions - no match rules-----------------
-instruct stkI_to_regF(regF dst, stackSlotI src) %{
- // No match rule to avoid chain rule match.
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
- format %{ "LDF $src,$dst\t! stkI to regF" %}
- opcode(Assembler::ldf_op3);
- ins_encode(simple_form3_mem_reg(src, dst));
- ins_pipe(floadF_stk);
-%}
-
-instruct stkL_to_regD(regD dst, stackSlotL src) %{
- // No match rule to avoid chain rule match.
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
- format %{ "LDDF $src,$dst\t! stkL to regD" %}
- opcode(Assembler::lddf_op3);
- ins_encode(simple_form3_mem_reg(src, dst));
- ins_pipe(floadD_stk);
-%}
-
-instruct regF_to_stkI(stackSlotI dst, regF src) %{
- // No match rule to avoid chain rule match.
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
- format %{ "STF $src,$dst\t! regF to stkI" %}
- opcode(Assembler::stf_op3);
- ins_encode(simple_form3_mem_reg(dst, src));
- ins_pipe(fstoreF_stk_reg);
-%}
-
-instruct regD_to_stkL(stackSlotL dst, regD src) %{
- // No match rule to avoid chain rule match.
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
- format %{ "STDF $src,$dst\t! regD to stkL" %}
- opcode(Assembler::stdf_op3);
- ins_encode(simple_form3_mem_reg(dst, src));
- ins_pipe(fstoreD_stk_reg);
-%}
-
-instruct regI_to_stkLHi(stackSlotL dst, iRegI src) %{
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST*2);
- format %{ "STW $src,$dst.hi\t! long\n\t"
- "STW R_G0,$dst.lo" %}
- opcode(Assembler::stw_op3);
- ins_encode(simple_form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, R_G0));
- ins_pipe(lstoreI_stk_reg);
-%}
-
-instruct regL_to_stkD(stackSlotD dst, iRegL src) %{
- // No match rule to avoid chain rule match.
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
- format %{ "STX $src,$dst\t! regL to stkD" %}
- opcode(Assembler::stx_op3);
- ins_encode(simple_form3_mem_reg( dst, src ) );
- ins_pipe(istore_stk_reg);
-%}
-
-//---------- Chain stack slots between similar types --------
-
-// Load integer from stack slot
-instruct stkI_to_regI( iRegI dst, stackSlotI src ) %{
- match(Set dst src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDUW $src,$dst\t!stk" %}
- opcode(Assembler::lduw_op3);
- ins_encode(simple_form3_mem_reg( src, dst ) );
- ins_pipe(iload_mem);
-%}
-
-// Store integer to stack slot
-instruct regI_to_stkI( stackSlotI dst, iRegI src ) %{
- match(Set dst src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STW $src,$dst\t!stk" %}
- opcode(Assembler::stw_op3);
- ins_encode(simple_form3_mem_reg( dst, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-// Load long from stack slot
-instruct stkL_to_regL( iRegL dst, stackSlotL src ) %{
- match(Set dst src);
-
- ins_cost(MEMORY_REF_COST);
- format %{ "LDX $src,$dst\t! long" %}
- opcode(Assembler::ldx_op3);
- ins_encode(simple_form3_mem_reg( src, dst ) );
- ins_pipe(iload_mem);
-%}
-
-// Store long to stack slot
-instruct regL_to_stkL(stackSlotL dst, iRegL src) %{
- match(Set dst src);
-
- ins_cost(MEMORY_REF_COST);
- format %{ "STX $src,$dst\t! long" %}
- opcode(Assembler::stx_op3);
- ins_encode(simple_form3_mem_reg( dst, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-// Load pointer from stack slot, 64-bit encoding
-instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{
- match(Set dst src);
- ins_cost(MEMORY_REF_COST);
- format %{ "LDX $src,$dst\t!ptr" %}
- opcode(Assembler::ldx_op3);
- ins_encode(simple_form3_mem_reg( src, dst ) );
- ins_pipe(iload_mem);
-%}
-
-// Store pointer to stack slot
-instruct regP_to_stkP(stackSlotP dst, iRegP src) %{
- match(Set dst src);
- ins_cost(MEMORY_REF_COST);
- format %{ "STX $src,$dst\t!ptr" %}
- opcode(Assembler::stx_op3);
- ins_encode(simple_form3_mem_reg( dst, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-//------------Special Nop instructions for bundling - no match rules-----------
-// Nop using the A0 functional unit
-instruct Nop_A0() %{
- ins_cost(0);
-
- format %{ "NOP ! Alu Pipeline" %}
- opcode(Assembler::or_op3, Assembler::arith_op);
- ins_encode( form2_nop() );
- ins_pipe(ialu_nop_A0);
-%}
-
-// Nop using the A1 functional unit
-instruct Nop_A1( ) %{
- ins_cost(0);
-
- format %{ "NOP ! Alu Pipeline" %}
- opcode(Assembler::or_op3, Assembler::arith_op);
- ins_encode( form2_nop() );
- ins_pipe(ialu_nop_A1);
-%}
-
-// Nop using the memory functional unit
-instruct Nop_MS( ) %{
- ins_cost(0);
-
- format %{ "NOP ! Memory Pipeline" %}
- ins_encode( emit_mem_nop );
- ins_pipe(mem_nop);
-%}
-
-// Nop using the floating add functional unit
-instruct Nop_FA( ) %{
- ins_cost(0);
-
- format %{ "NOP ! Floating Add Pipeline" %}
- ins_encode( emit_fadd_nop );
- ins_pipe(fadd_nop);
-%}
-
-// Nop using the branch functional unit
-instruct Nop_BR( ) %{
- ins_cost(0);
-
- format %{ "NOP ! Branch Pipeline" %}
- ins_encode( emit_br_nop );
- ins_pipe(br_nop);
-%}
-
-//----------Load/Store/Move Instructions---------------------------------------
-//----------Load Instructions--------------------------------------------------
-// Load Byte (8bit signed)
-instruct loadB(iRegI dst, memory mem) %{
- match(Set dst (LoadB mem));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDSB $mem,$dst\t! byte" %}
- ins_encode %{
- __ ldsb($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Byte (8bit signed) into a Long Register
-instruct loadB2L(iRegL dst, memory mem) %{
- match(Set dst (ConvI2L (LoadB mem)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDSB $mem,$dst\t! byte -> long" %}
- ins_encode %{
- __ ldsb($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Unsigned Byte (8bit UNsigned) into an int reg
-instruct loadUB(iRegI dst, memory mem) %{
- match(Set dst (LoadUB mem));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUB $mem,$dst\t! ubyte" %}
- ins_encode %{
- __ ldub($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Unsigned Byte (8bit UNsigned) into a Long Register
-instruct loadUB2L(iRegL dst, memory mem) %{
- match(Set dst (ConvI2L (LoadUB mem)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUB $mem,$dst\t! ubyte -> long" %}
- ins_encode %{
- __ ldub($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Unsigned Byte (8 bit UNsigned) with 32-bit mask into Long Register
-instruct loadUB2L_immI(iRegL dst, memory mem, immI mask) %{
- match(Set dst (ConvI2L (AndI (LoadUB mem) mask)));
- ins_cost(MEMORY_REF_COST + DEFAULT_COST);
-
- size(2*4);
- format %{ "LDUB $mem,$dst\t# ubyte & 32-bit mask -> long\n\t"
- "AND $dst,right_n_bits($mask, 8),$dst" %}
- ins_encode %{
- __ ldub($mem$$Address, $dst$$Register);
- __ and3($dst$$Register, $mask$$constant & right_n_bits(8), $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Short (16bit signed)
-instruct loadS(iRegI dst, memory mem) %{
- match(Set dst (LoadS mem));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDSH $mem,$dst\t! short" %}
- ins_encode %{
- __ ldsh($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Short (16 bit signed) to Byte (8 bit signed)
-instruct loadS2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{
- match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
-
- format %{ "LDSB $mem+1,$dst\t! short -> byte" %}
- ins_encode %{
- __ ldsb($mem$$Address, $dst$$Register, 1);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Short (16bit signed) into a Long Register
-instruct loadS2L(iRegL dst, memory mem) %{
- match(Set dst (ConvI2L (LoadS mem)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDSH $mem,$dst\t! short -> long" %}
- ins_encode %{
- __ ldsh($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Unsigned Short/Char (16bit UNsigned)
-instruct loadUS(iRegI dst, memory mem) %{
- match(Set dst (LoadUS mem));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUH $mem,$dst\t! ushort/char" %}
- ins_encode %{
- __ lduh($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed)
-instruct loadUS2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{
- match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDSB $mem+1,$dst\t! ushort -> byte" %}
- ins_encode %{
- __ ldsb($mem$$Address, $dst$$Register, 1);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Unsigned Short/Char (16bit UNsigned) into a Long Register
-instruct loadUS2L(iRegL dst, memory mem) %{
- match(Set dst (ConvI2L (LoadUS mem)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUH $mem,$dst\t! ushort/char -> long" %}
- ins_encode %{
- __ lduh($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Unsigned Short/Char (16bit UNsigned) with mask 0xFF into a Long Register
-instruct loadUS2L_immI_255(iRegL dst, indOffset13m7 mem, immI_255 mask) %{
- match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUB $mem+1,$dst\t! ushort/char & 0xFF -> long" %}
- ins_encode %{
- __ ldub($mem$$Address, $dst$$Register, 1); // LSB is index+1 on BE
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Unsigned Short/Char (16bit UNsigned) with a 13-bit mask into a Long Register
-instruct loadUS2L_immI13(iRegL dst, memory mem, immI13 mask) %{
- match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
- ins_cost(MEMORY_REF_COST + DEFAULT_COST);
-
- size(2*4);
- format %{ "LDUH $mem,$dst\t! ushort/char & 13-bit mask -> long\n\t"
- "AND $dst,$mask,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- __ lduh($mem$$Address, Rdst);
- __ and3(Rdst, $mask$$constant, Rdst);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Unsigned Short/Char (16bit UNsigned) with a 32-bit mask into a Long Register
-instruct loadUS2L_immI(iRegL dst, memory mem, immI mask, iRegL tmp) %{
- match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
- effect(TEMP dst, TEMP tmp);
- ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
-
- format %{ "LDUH $mem,$dst\t! ushort/char & 32-bit mask -> long\n\t"
- "SET right_n_bits($mask, 16),$tmp\n\t"
- "AND $dst,$tmp,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- Register Rtmp = $tmp$$Register;
- __ lduh($mem$$Address, Rdst);
- __ set($mask$$constant & right_n_bits(16), Rtmp);
- __ and3(Rdst, Rtmp, Rdst);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Integer
-instruct loadI(iRegI dst, memory mem) %{
- match(Set dst (LoadI mem));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUW $mem,$dst\t! int" %}
- ins_encode %{
- __ lduw($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Integer to Byte (8 bit signed)
-instruct loadI2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{
- match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
-
- format %{ "LDSB $mem+3,$dst\t! int -> byte" %}
- ins_encode %{
- __ ldsb($mem$$Address, $dst$$Register, 3);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Integer to Unsigned Byte (8 bit UNsigned)
-instruct loadI2UB(iRegI dst, indOffset13m7 mem, immI_255 mask) %{
- match(Set dst (AndI (LoadI mem) mask));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
-
- format %{ "LDUB $mem+3,$dst\t! int -> ubyte" %}
- ins_encode %{
- __ ldub($mem$$Address, $dst$$Register, 3);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Integer to Short (16 bit signed)
-instruct loadI2S(iRegI dst, indOffset13m7 mem, immI_16 sixteen) %{
- match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
-
- format %{ "LDSH $mem+2,$dst\t! int -> short" %}
- ins_encode %{
- __ ldsh($mem$$Address, $dst$$Register, 2);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Integer to Unsigned Short (16 bit UNsigned)
-instruct loadI2US(iRegI dst, indOffset13m7 mem, immI_65535 mask) %{
- match(Set dst (AndI (LoadI mem) mask));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
-
- format %{ "LDUH $mem+2,$dst\t! int -> ushort/char" %}
- ins_encode %{
- __ lduh($mem$$Address, $dst$$Register, 2);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Integer into a Long Register
-instruct loadI2L(iRegL dst, memory mem) %{
- match(Set dst (ConvI2L (LoadI mem)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDSW $mem,$dst\t! int -> long" %}
- ins_encode %{
- __ ldsw($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mask_mem);
-%}
-
-// Load Integer with mask 0xFF into a Long Register
-instruct loadI2L_immI_255(iRegL dst, indOffset13m7 mem, immI_255 mask) %{
- match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUB $mem+3,$dst\t! int & 0xFF -> long" %}
- ins_encode %{
- __ ldub($mem$$Address, $dst$$Register, 3); // LSB is index+3 on BE
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Integer with mask 0xFFFF into a Long Register
-instruct loadI2L_immI_65535(iRegL dst, indOffset13m7 mem, immI_65535 mask) %{
- match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUH $mem+2,$dst\t! int & 0xFFFF -> long" %}
- ins_encode %{
- __ lduh($mem$$Address, $dst$$Register, 2); // LSW is index+2 on BE
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Integer with a 12-bit mask into a Long Register
-instruct loadI2L_immU12(iRegL dst, memory mem, immU12 mask) %{
- match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
- ins_cost(MEMORY_REF_COST + DEFAULT_COST);
-
- size(2*4);
- format %{ "LDUW $mem,$dst\t! int & 12-bit mask -> long\n\t"
- "AND $dst,$mask,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- __ lduw($mem$$Address, Rdst);
- __ and3(Rdst, $mask$$constant, Rdst);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Integer with a 31-bit mask into a Long Register
-instruct loadI2L_immU31(iRegL dst, memory mem, immU31 mask, iRegL tmp) %{
- match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
- effect(TEMP dst, TEMP tmp);
- ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
-
- format %{ "LDUW $mem,$dst\t! int & 31-bit mask -> long\n\t"
- "SET $mask,$tmp\n\t"
- "AND $dst,$tmp,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- Register Rtmp = $tmp$$Register;
- __ lduw($mem$$Address, Rdst);
- __ set($mask$$constant, Rtmp);
- __ and3(Rdst, Rtmp, Rdst);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Unsigned Integer into a Long Register
-instruct loadUI2L(iRegL dst, memory mem, immL_32bits mask) %{
- match(Set dst (AndL (ConvI2L (LoadI mem)) mask));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDUW $mem,$dst\t! uint -> long" %}
- ins_encode %{
- __ lduw($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Long - aligned
-instruct loadL(iRegL dst, memory mem ) %{
- match(Set dst (LoadL mem));
- ins_cost(MEMORY_REF_COST);
-
- size(4);
- format %{ "LDX $mem,$dst\t! long" %}
- ins_encode %{
- __ ldx($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Long - UNaligned
-instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{
- match(Set dst (LoadL_unaligned mem));
- effect(KILL tmp);
- ins_cost(MEMORY_REF_COST*2+DEFAULT_COST);
- format %{ "LDUW $mem+4,R_O7\t! misaligned long\n"
- "\tLDUW $mem ,$dst\n"
- "\tSLLX #32, $dst, $dst\n"
- "\tOR $dst, R_O7, $dst" %}
- opcode(Assembler::lduw_op3);
- ins_encode(form3_mem_reg_long_unaligned_marshal( mem, dst ));
- ins_pipe(iload_mem);
-%}
-
-// Load Range
-instruct loadRange(iRegI dst, memory mem) %{
- match(Set dst (LoadRange mem));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDUW $mem,$dst\t! range" %}
- opcode(Assembler::lduw_op3);
- ins_encode(simple_form3_mem_reg( mem, dst ) );
- ins_pipe(iload_mem);
-%}
-
-// Load Integer into %f register (for fitos/fitod)
-instruct loadI_freg(regF dst, memory mem) %{
- match(Set dst (LoadI mem));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDF $mem,$dst\t! for fitos/fitod" %}
- opcode(Assembler::ldf_op3);
- ins_encode(simple_form3_mem_reg( mem, dst ) );
- ins_pipe(floadF_mem);
-%}
-
-// Load Pointer
-instruct loadP(iRegP dst, memory mem) %{
- match(Set dst (LoadP mem));
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "LDX $mem,$dst\t! ptr" %}
- ins_encode %{
- __ ldx($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Compressed Pointer
-instruct loadN(iRegN dst, memory mem) %{
- match(Set dst (LoadN mem));
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "LDUW $mem,$dst\t! compressed ptr" %}
- ins_encode %{
- __ lduw($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Klass Pointer
-instruct loadKlass(iRegP dst, memory mem) %{
- match(Set dst (LoadKlass mem));
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "LDX $mem,$dst\t! klass ptr" %}
- ins_encode %{
- __ ldx($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load narrow Klass Pointer
-instruct loadNKlass(iRegN dst, memory mem) %{
- match(Set dst (LoadNKlass mem));
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "LDUW $mem,$dst\t! compressed klass ptr" %}
- ins_encode %{
- __ lduw($mem$$Address, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Double
-instruct loadD(regD dst, memory mem) %{
- match(Set dst (LoadD mem));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDDF $mem,$dst" %}
- opcode(Assembler::lddf_op3);
- ins_encode(simple_form3_mem_reg( mem, dst ) );
- ins_pipe(floadD_mem);
-%}
-
-// Load Double - UNaligned
-instruct loadD_unaligned(regD_low dst, memory mem ) %{
- match(Set dst (LoadD_unaligned mem));
- ins_cost(MEMORY_REF_COST*2+DEFAULT_COST);
- format %{ "LDF $mem ,$dst.hi\t! misaligned double\n"
- "\tLDF $mem+4,$dst.lo\t!" %}
- opcode(Assembler::ldf_op3);
- ins_encode( form3_mem_reg_double_unaligned( mem, dst ));
- ins_pipe(iload_mem);
-%}
-
-// Load Float
-instruct loadF(regF dst, memory mem) %{
- match(Set dst (LoadF mem));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDF $mem,$dst" %}
- opcode(Assembler::ldf_op3);
- ins_encode(simple_form3_mem_reg( mem, dst ) );
- ins_pipe(floadF_mem);
-%}
-
-// Load Constant
-instruct loadConI( iRegI dst, immI src ) %{
- match(Set dst src);
- ins_cost(DEFAULT_COST * 3/2);
- format %{ "SET $src,$dst" %}
- ins_encode( Set32(src, dst) );
- ins_pipe(ialu_hi_lo_reg);
-%}
-
-instruct loadConI13( iRegI dst, immI13 src ) %{
- match(Set dst src);
-
- size(4);
- format %{ "MOV $src,$dst" %}
- ins_encode( Set13( src, dst ) );
- ins_pipe(ialu_imm);
-%}
-
-instruct loadConP_set(iRegP dst, immP_set con) %{
- match(Set dst con);
- ins_cost(DEFAULT_COST * 3/2);
- format %{ "SET $con,$dst\t! ptr" %}
- ins_encode %{
- relocInfo::relocType constant_reloc = _opnds[1]->constant_reloc();
- intptr_t val = $con$$constant;
- if (constant_reloc == relocInfo::oop_type) {
- __ set_oop_constant((jobject) val, $dst$$Register);
- } else if (constant_reloc == relocInfo::metadata_type) {
- __ set_metadata_constant((Metadata*)val, $dst$$Register);
- } else { // non-oop pointers, e.g. card mark base, heap top
- assert(constant_reloc == relocInfo::none, "unexpected reloc type");
- __ set(val, $dst$$Register);
- }
- %}
- ins_pipe(loadConP);
-%}
-
-instruct loadConP_load(iRegP dst, immP_load con) %{
- match(Set dst con);
- ins_cost(MEMORY_REF_COST);
- format %{ "LD [$constanttablebase + $constantoffset],$dst\t! load from constant table: ptr=$con" %}
- ins_encode %{
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $dst$$Register);
- __ ld_ptr($constanttablebase, con_offset, $dst$$Register);
- %}
- ins_pipe(loadConP);
-%}
-
-instruct loadConP_no_oop_cheap(iRegP dst, immP_no_oop_cheap con) %{
- match(Set dst con);
- ins_cost(DEFAULT_COST * 3/2);
- format %{ "SET $con,$dst\t! non-oop ptr" %}
- ins_encode %{
- if (_opnds[1]->constant_reloc() == relocInfo::metadata_type) {
- __ set_metadata_constant((Metadata*)$con$$constant, $dst$$Register);
- } else {
- __ set($con$$constant, $dst$$Register);
- }
- %}
- ins_pipe(loadConP);
-%}
-
-instruct loadConP0(iRegP dst, immP0 src) %{
- match(Set dst src);
-
- size(4);
- format %{ "CLR $dst\t!ptr" %}
- ins_encode %{
- __ clr($dst$$Register);
- %}
- ins_pipe(ialu_imm);
-%}
-
-instruct loadConN0(iRegN dst, immN0 src) %{
- match(Set dst src);
-
- size(4);
- format %{ "CLR $dst\t! compressed NULL ptr" %}
- ins_encode %{
- __ clr($dst$$Register);
- %}
- ins_pipe(ialu_imm);
-%}
-
-instruct loadConN(iRegN dst, immN src) %{
- match(Set dst src);
- ins_cost(DEFAULT_COST * 3/2);
- format %{ "SET $src,$dst\t! compressed ptr" %}
- ins_encode %{
- Register dst = $dst$$Register;
- __ set_narrow_oop((jobject)$src$$constant, dst);
- %}
- ins_pipe(ialu_hi_lo_reg);
-%}
-
-instruct loadConNKlass(iRegN dst, immNKlass src) %{
- match(Set dst src);
- ins_cost(DEFAULT_COST * 3/2);
- format %{ "SET $src,$dst\t! compressed klass ptr" %}
- ins_encode %{
- Register dst = $dst$$Register;
- __ set_narrow_klass((Klass*)$src$$constant, dst);
- %}
- ins_pipe(ialu_hi_lo_reg);
-%}
-
-// Materialize long value (predicated by immL_cheap).
-instruct loadConL_set64(iRegL dst, immL_cheap con, o7RegL tmp) %{
- match(Set dst con);
- effect(KILL tmp);
- ins_cost(DEFAULT_COST * 3);
- format %{ "SET64 $con,$dst KILL $tmp\t! cheap long" %}
- ins_encode %{
- __ set64($con$$constant, $dst$$Register, $tmp$$Register);
- %}
- ins_pipe(loadConL);
-%}
-
-// Load long value from constant table (predicated by immL_expensive).
-instruct loadConL_ldx(iRegL dst, immL_expensive con) %{
- match(Set dst con);
- ins_cost(MEMORY_REF_COST);
- format %{ "LDX [$constanttablebase + $constantoffset],$dst\t! load from constant table: long=$con" %}
- ins_encode %{
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $dst$$Register);
- __ ldx($constanttablebase, con_offset, $dst$$Register);
- %}
- ins_pipe(loadConL);
-%}
-
-instruct loadConL0( iRegL dst, immL0 src ) %{
- match(Set dst src);
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "CLR $dst\t! long" %}
- ins_encode( Set13( src, dst ) );
- ins_pipe(ialu_imm);
-%}
-
-instruct loadConL13( iRegL dst, immL13 src ) %{
- match(Set dst src);
- ins_cost(DEFAULT_COST * 2);
-
- size(4);
- format %{ "MOV $src,$dst\t! long" %}
- ins_encode( Set13( src, dst ) );
- ins_pipe(ialu_imm);
-%}
-
-instruct loadConF(regF dst, immF con, o7RegI tmp) %{
- match(Set dst con);
- effect(KILL tmp);
- format %{ "LDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: float=$con" %}
- ins_encode %{
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $tmp$$Register);
- __ ldf(FloatRegisterImpl::S, $constanttablebase, con_offset, $dst$$FloatRegister);
- %}
- ins_pipe(loadConFD);
-%}
-
-instruct loadConD(regD dst, immD con, o7RegI tmp) %{
- match(Set dst con);
- effect(KILL tmp);
- format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: double=$con" %}
- ins_encode %{
- // XXX This is a quick fix for 6833573.
- //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset($con), $dst$$FloatRegister);
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $tmp$$Register);
- __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(loadConFD);
-%}
-
-// Prefetch instructions for allocation.
-// Must be safe to execute with invalid address (cannot fault).
-
-instruct prefetchAlloc( memory mem ) %{
- predicate(AllocatePrefetchInstr == 0);
- match( PrefetchAllocation mem );
- ins_cost(MEMORY_REF_COST);
-
- format %{ "PREFETCH $mem,2\t! Prefetch allocation" %}
- opcode(Assembler::prefetch_op3);
- ins_encode( form3_mem_prefetch_write( mem ) );
- ins_pipe(iload_mem);
-%}
-
-// Use BIS instruction to prefetch for allocation.
-// Could fault, need space at the end of TLAB.
-instruct prefetchAlloc_bis( iRegP dst ) %{
- predicate(AllocatePrefetchInstr == 1);
- match( PrefetchAllocation dst );
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "STXA [$dst]\t! // Prefetch allocation using BIS" %}
- ins_encode %{
- __ stxa(G0, $dst$$Register, G0, Assembler::ASI_ST_BLKINIT_PRIMARY);
- %}
- ins_pipe(istore_mem_reg);
-%}
-
-// Next code is used for finding next cache line address to prefetch.
-instruct cacheLineAdr( iRegP dst, iRegP src, immL13 mask ) %{
- match(Set dst (CastX2P (AndL (CastP2X src) mask)));
- ins_cost(DEFAULT_COST);
- size(4);
-
- format %{ "AND $src,$mask,$dst\t! next cache line address" %}
- ins_encode %{
- __ and3($src$$Register, $mask$$constant, $dst$$Register);
- %}
- ins_pipe(ialu_reg_imm);
-%}
-
-//----------Store Instructions-------------------------------------------------
-// Store Byte
-instruct storeB(memory mem, iRegI src) %{
- match(Set mem (StoreB mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STB $src,$mem\t! byte" %}
- opcode(Assembler::stb_op3);
- ins_encode(simple_form3_mem_reg( mem, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-instruct storeB0(memory mem, immI0 src) %{
- match(Set mem (StoreB mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STB $src,$mem\t! byte" %}
- opcode(Assembler::stb_op3);
- ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
- ins_pipe(istore_mem_zero);
-%}
-
-instruct storeCM0(memory mem, immI0 src) %{
- match(Set mem (StoreCM mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STB $src,$mem\t! CMS card-mark byte 0" %}
- opcode(Assembler::stb_op3);
- ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
- ins_pipe(istore_mem_zero);
-%}
-
-// Store Char/Short
-instruct storeC(memory mem, iRegI src) %{
- match(Set mem (StoreC mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STH $src,$mem\t! short" %}
- opcode(Assembler::sth_op3);
- ins_encode(simple_form3_mem_reg( mem, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-instruct storeC0(memory mem, immI0 src) %{
- match(Set mem (StoreC mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STH $src,$mem\t! short" %}
- opcode(Assembler::sth_op3);
- ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
- ins_pipe(istore_mem_zero);
-%}
-
-// Store Integer
-instruct storeI(memory mem, iRegI src) %{
- match(Set mem (StoreI mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STW $src,$mem" %}
- opcode(Assembler::stw_op3);
- ins_encode(simple_form3_mem_reg( mem, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-// Store Long
-instruct storeL(memory mem, iRegL src) %{
- match(Set mem (StoreL mem src));
- ins_cost(MEMORY_REF_COST);
- format %{ "STX $src,$mem\t! long" %}
- opcode(Assembler::stx_op3);
- ins_encode(simple_form3_mem_reg( mem, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-instruct storeI0(memory mem, immI0 src) %{
- match(Set mem (StoreI mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STW $src,$mem" %}
- opcode(Assembler::stw_op3);
- ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
- ins_pipe(istore_mem_zero);
-%}
-
-instruct storeL0(memory mem, immL0 src) %{
- match(Set mem (StoreL mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STX $src,$mem" %}
- opcode(Assembler::stx_op3);
- ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
- ins_pipe(istore_mem_zero);
-%}
-
-// Store Integer from float register (used after fstoi)
-instruct storeI_Freg(memory mem, regF src) %{
- match(Set mem (StoreI mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STF $src,$mem\t! after fstoi/fdtoi" %}
- opcode(Assembler::stf_op3);
- ins_encode(simple_form3_mem_reg( mem, src ) );
- ins_pipe(fstoreF_mem_reg);
-%}
-
-// Store Pointer
-instruct storeP(memory dst, sp_ptr_RegP src) %{
- match(Set dst (StoreP dst src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STX $src,$dst\t! ptr" %}
- opcode(Assembler::stx_op3, 0, REGP_OP);
- ins_encode( form3_mem_reg( dst, src ) );
- ins_pipe(istore_mem_spORreg);
-%}
-
-instruct storeP0(memory dst, immP0 src) %{
- match(Set dst (StoreP dst src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STX $src,$dst\t! ptr" %}
- opcode(Assembler::stx_op3, 0, REGP_OP);
- ins_encode( form3_mem_reg( dst, R_G0 ) );
- ins_pipe(istore_mem_zero);
-%}
-
-// Store Compressed Pointer
-instruct storeN(memory dst, iRegN src) %{
- match(Set dst (StoreN dst src));
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "STW $src,$dst\t! compressed ptr" %}
- ins_encode %{
- Register base = as_Register($dst$$base);
- Register index = as_Register($dst$$index);
- Register src = $src$$Register;
- if (index != G0) {
- __ stw(src, base, index);
- } else {
- __ stw(src, base, $dst$$disp);
- }
- %}
- ins_pipe(istore_mem_spORreg);
-%}
-
-instruct storeNKlass(memory dst, iRegN src) %{
- match(Set dst (StoreNKlass dst src));
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "STW $src,$dst\t! compressed klass ptr" %}
- ins_encode %{
- Register base = as_Register($dst$$base);
- Register index = as_Register($dst$$index);
- Register src = $src$$Register;
- if (index != G0) {
- __ stw(src, base, index);
- } else {
- __ stw(src, base, $dst$$disp);
- }
- %}
- ins_pipe(istore_mem_spORreg);
-%}
-
-instruct storeN0(memory dst, immN0 src) %{
- match(Set dst (StoreN dst src));
- ins_cost(MEMORY_REF_COST);
- size(4);
-
- format %{ "STW $src,$dst\t! compressed ptr" %}
- ins_encode %{
- Register base = as_Register($dst$$base);
- Register index = as_Register($dst$$index);
- if (index != G0) {
- __ stw(0, base, index);
- } else {
- __ stw(0, base, $dst$$disp);
- }
- %}
- ins_pipe(istore_mem_zero);
-%}
-
-// Store Double
-instruct storeD( memory mem, regD src) %{
- match(Set mem (StoreD mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STDF $src,$mem" %}
- opcode(Assembler::stdf_op3);
- ins_encode(simple_form3_mem_reg( mem, src ) );
- ins_pipe(fstoreD_mem_reg);
-%}
-
-instruct storeD0( memory mem, immD0 src) %{
- match(Set mem (StoreD mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STX $src,$mem" %}
- opcode(Assembler::stx_op3);
- ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
- ins_pipe(fstoreD_mem_zero);
-%}
-
-// Store Float
-instruct storeF( memory mem, regF src) %{
- match(Set mem (StoreF mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STF $src,$mem" %}
- opcode(Assembler::stf_op3);
- ins_encode(simple_form3_mem_reg( mem, src ) );
- ins_pipe(fstoreF_mem_reg);
-%}
-
-instruct storeF0( memory mem, immF0 src) %{
- match(Set mem (StoreF mem src));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STW $src,$mem\t! storeF0" %}
- opcode(Assembler::stw_op3);
- ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
- ins_pipe(fstoreF_mem_zero);
-%}
-
-// Convert oop pointer into compressed form
-instruct encodeHeapOop(iRegN dst, iRegP src) %{
- predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull);
- match(Set dst (EncodeP src));
- format %{ "encode_heap_oop $src, $dst" %}
- ins_encode %{
- __ encode_heap_oop($src$$Register, $dst$$Register);
- %}
- ins_avoid_back_to_back(CompressedOops::base() == NULL ? AVOID_NONE : AVOID_BEFORE);
- ins_pipe(ialu_reg);
-%}
-
-instruct encodeHeapOop_not_null(iRegN dst, iRegP src) %{
- predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull);
- match(Set dst (EncodeP src));
- format %{ "encode_heap_oop_not_null $src, $dst" %}
- ins_encode %{
- __ encode_heap_oop_not_null($src$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-instruct decodeHeapOop(iRegP dst, iRegN src) %{
- predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull &&
- n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant);
- match(Set dst (DecodeN src));
- format %{ "decode_heap_oop $src, $dst" %}
- ins_encode %{
- __ decode_heap_oop($src$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-instruct decodeHeapOop_not_null(iRegP dst, iRegN src) %{
- predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull ||
- n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant);
- match(Set dst (DecodeN src));
- format %{ "decode_heap_oop_not_null $src, $dst" %}
- ins_encode %{
- __ decode_heap_oop_not_null($src$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-instruct encodeKlass_not_null(iRegN dst, iRegP src) %{
- match(Set dst (EncodePKlass src));
- format %{ "encode_klass_not_null $src, $dst" %}
- ins_encode %{
- __ encode_klass_not_null($src$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-instruct decodeKlass_not_null(iRegP dst, iRegN src) %{
- match(Set dst (DecodeNKlass src));
- format %{ "decode_klass_not_null $src, $dst" %}
- ins_encode %{
- __ decode_klass_not_null($src$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-//----------MemBar Instructions-----------------------------------------------
-// Memory barrier flavors
-
-instruct membar_acquire() %{
- match(MemBarAcquire);
- match(LoadFence);
- ins_cost(4*MEMORY_REF_COST);
-
- size(0);
- format %{ "MEMBAR-acquire" %}
- ins_encode( enc_membar_acquire );
- ins_pipe(long_memory_op);
-%}
-
-instruct membar_acquire_lock() %{
- match(MemBarAcquireLock);
- ins_cost(0);
-
- size(0);
- format %{ "!MEMBAR-acquire (CAS in prior FastLock so empty encoding)" %}
- ins_encode( );
- ins_pipe(empty);
-%}
-
-instruct membar_release() %{
- match(MemBarRelease);
- match(StoreFence);
- ins_cost(4*MEMORY_REF_COST);
-
- size(0);
- format %{ "MEMBAR-release" %}
- ins_encode( enc_membar_release );
- ins_pipe(long_memory_op);
-%}
-
-instruct membar_release_lock() %{
- match(MemBarReleaseLock);
- ins_cost(0);
-
- size(0);
- format %{ "!MEMBAR-release (CAS in succeeding FastUnlock so empty encoding)" %}
- ins_encode( );
- ins_pipe(empty);
-%}
-
-instruct membar_volatile() %{
- match(MemBarVolatile);
- ins_cost(4*MEMORY_REF_COST);
-
- size(4);
- format %{ "MEMBAR-volatile" %}
- ins_encode( enc_membar_volatile );
- ins_pipe(long_memory_op);
-%}
-
-instruct unnecessary_membar_volatile() %{
- match(MemBarVolatile);
- predicate(Matcher::post_store_load_barrier(n));
- ins_cost(0);
-
- size(0);
- format %{ "!MEMBAR-volatile (unnecessary so empty encoding)" %}
- ins_encode( );
- ins_pipe(empty);
-%}
-
-instruct membar_storestore() %{
- match(MemBarStoreStore);
- ins_cost(0);
-
- size(0);
- format %{ "!MEMBAR-storestore (empty encoding)" %}
- ins_encode( );
- ins_pipe(empty);
-%}
-
-//----------Register Move Instructions-----------------------------------------
-instruct roundDouble_nop(regD dst) %{
- match(Set dst (RoundDouble dst));
- ins_cost(0);
- // SPARC results are already "rounded" (i.e., normal-format IEEE)
- ins_encode( );
- ins_pipe(empty);
-%}
-
-
-instruct roundFloat_nop(regF dst) %{
- match(Set dst (RoundFloat dst));
- ins_cost(0);
- // SPARC results are already "rounded" (i.e., normal-format IEEE)
- ins_encode( );
- ins_pipe(empty);
-%}
-
-
-// Cast Index to Pointer for unsafe natives
-instruct castX2P(iRegX src, iRegP dst) %{
- match(Set dst (CastX2P src));
-
- format %{ "MOV $src,$dst\t! IntX->Ptr" %}
- ins_encode( form3_g0_rs2_rd_move( src, dst ) );
- ins_pipe(ialu_reg);
-%}
-
-// Cast Pointer to Index for unsafe natives
-instruct castP2X(iRegP src, iRegX dst) %{
- match(Set dst (CastP2X src));
-
- format %{ "MOV $src,$dst\t! Ptr->IntX" %}
- ins_encode( form3_g0_rs2_rd_move( src, dst ) );
- ins_pipe(ialu_reg);
-%}
-
-instruct stfSSD(stackSlotD stkSlot, regD src) %{
- // %%%% TO DO: Tell the coalescer that this kind of node is a copy!
- match(Set stkSlot src); // chain rule
- ins_cost(MEMORY_REF_COST);
- format %{ "STDF $src,$stkSlot\t!stk" %}
- opcode(Assembler::stdf_op3);
- ins_encode(simple_form3_mem_reg(stkSlot, src));
- ins_pipe(fstoreD_stk_reg);
-%}
-
-instruct ldfSSD(regD dst, stackSlotD stkSlot) %{
- // %%%% TO DO: Tell the coalescer that this kind of node is a copy!
- match(Set dst stkSlot); // chain rule
- ins_cost(MEMORY_REF_COST);
- format %{ "LDDF $stkSlot,$dst\t!stk" %}
- opcode(Assembler::lddf_op3);
- ins_encode(simple_form3_mem_reg(stkSlot, dst));
- ins_pipe(floadD_stk);
-%}
-
-instruct stfSSF(stackSlotF stkSlot, regF src) %{
- // %%%% TO DO: Tell the coalescer that this kind of node is a copy!
- match(Set stkSlot src); // chain rule
- ins_cost(MEMORY_REF_COST);
- format %{ "STF $src,$stkSlot\t!stk" %}
- opcode(Assembler::stf_op3);
- ins_encode(simple_form3_mem_reg(stkSlot, src));
- ins_pipe(fstoreF_stk_reg);
-%}
-
-//----------Conditional Move---------------------------------------------------
-// Conditional move
-instruct cmovIP_reg(cmpOpP cmp, flagsRegP pcc, iRegI dst, iRegI src) %{
- match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $pcc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovIP_imm(cmpOpP cmp, flagsRegP pcc, iRegI dst, immI11 src) %{
- match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
- ins_cost(140);
- format %{ "MOV$cmp $pcc,$src,$dst" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovII_reg(cmpOp cmp, flagsReg icc, iRegI dst, iRegI src) %{
- match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovII_imm(cmpOp cmp, flagsReg icc, iRegI dst, immI11 src) %{
- match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
- ins_cost(140);
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovIIu_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{
- match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovIIu_imm(cmpOpU cmp, flagsRegU icc, iRegI dst, immI11 src) %{
- match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
- ins_cost(140);
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovIF_reg(cmpOpF cmp, flagsRegF fcc, iRegI dst, iRegI src) %{
- match(Set dst (CMoveI (Binary cmp fcc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "MOV$cmp $fcc,$src,$dst" %}
- ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovIF_imm(cmpOpF cmp, flagsRegF fcc, iRegI dst, immI11 src) %{
- match(Set dst (CMoveI (Binary cmp fcc) (Binary dst src)));
- ins_cost(140);
- size(4);
- format %{ "MOV$cmp $fcc,$src,$dst" %}
- ins_encode( enc_cmov_imm_f(cmp,dst,src, fcc) );
- ins_pipe(ialu_imm);
-%}
-
-// Conditional move for RegN. Only cmov(reg,reg).
-instruct cmovNP_reg(cmpOpP cmp, flagsRegP pcc, iRegN dst, iRegN src) %{
- match(Set dst (CMoveN (Binary cmp pcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $pcc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(ialu_reg);
-%}
-
-// This instruction also works with CmpN so we don't need cmovNN_reg.
-instruct cmovNI_reg(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src) %{
- match(Set dst (CMoveN (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-// This instruction also works with CmpN so we don't need cmovNN_reg.
-instruct cmovNIu_reg(cmpOpU cmp, flagsRegU icc, iRegN dst, iRegN src) %{
- match(Set dst (CMoveN (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovNF_reg(cmpOpF cmp, flagsRegF fcc, iRegN dst, iRegN src) %{
- match(Set dst (CMoveN (Binary cmp fcc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "MOV$cmp $fcc,$src,$dst" %}
- ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) );
- ins_pipe(ialu_reg);
-%}
-
-// Conditional move
-instruct cmovPP_reg(cmpOpP cmp, flagsRegP pcc, iRegP dst, iRegP src) %{
- match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $pcc,$src,$dst\t! ptr" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovPP_imm(cmpOpP cmp, flagsRegP pcc, iRegP dst, immP0 src) %{
- match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
- ins_cost(140);
- format %{ "MOV$cmp $pcc,$src,$dst\t! ptr" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(ialu_imm);
-%}
-
-// This instruction also works with CmpN so we don't need cmovPN_reg.
-instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{
- match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovPIu_reg(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src) %{
- match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{
- match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
- ins_cost(140);
-
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovPIu_imm(cmpOpU cmp, flagsRegU icc, iRegP dst, immP0 src) %{
- match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
- ins_cost(140);
-
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovPF_reg(cmpOpF cmp, flagsRegF fcc, iRegP dst, iRegP src) %{
- match(Set dst (CMoveP (Binary cmp fcc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "MOV$cmp $fcc,$src,$dst" %}
- ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovPF_imm(cmpOpF cmp, flagsRegF fcc, iRegP dst, immP0 src) %{
- match(Set dst (CMoveP (Binary cmp fcc) (Binary dst src)));
- ins_cost(140);
- size(4);
- format %{ "MOV$cmp $fcc,$src,$dst" %}
- ins_encode( enc_cmov_imm_f(cmp,dst,src, fcc) );
- ins_pipe(ialu_imm);
-%}
-
-// Conditional move
-instruct cmovFP_reg(cmpOpP cmp, flagsRegP pcc, regF dst, regF src) %{
- match(Set dst (CMoveF (Binary cmp pcc) (Binary dst src)));
- ins_cost(150);
- opcode(0x101);
- format %{ "FMOVD$cmp $pcc,$src,$dst" %}
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(int_conditional_float_move);
-%}
-
-instruct cmovFI_reg(cmpOp cmp, flagsReg icc, regF dst, regF src) %{
- match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "FMOVS$cmp $icc,$src,$dst" %}
- opcode(0x101);
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(int_conditional_float_move);
-%}
-
-instruct cmovFIu_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src) %{
- match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "FMOVS$cmp $icc,$src,$dst" %}
- opcode(0x101);
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(int_conditional_float_move);
-%}
-
-// Conditional move,
-instruct cmovFF_reg(cmpOpF cmp, flagsRegF fcc, regF dst, regF src) %{
- match(Set dst (CMoveF (Binary cmp fcc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "FMOVF$cmp $fcc,$src,$dst" %}
- opcode(0x1);
- ins_encode( enc_cmovff_reg(cmp,fcc,dst,src) );
- ins_pipe(int_conditional_double_move);
-%}
-
-// Conditional move
-instruct cmovDP_reg(cmpOpP cmp, flagsRegP pcc, regD dst, regD src) %{
- match(Set dst (CMoveD (Binary cmp pcc) (Binary dst src)));
- ins_cost(150);
- size(4);
- opcode(0x102);
- format %{ "FMOVD$cmp $pcc,$src,$dst" %}
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(int_conditional_double_move);
-%}
-
-instruct cmovDI_reg(cmpOp cmp, flagsReg icc, regD dst, regD src) %{
- match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "FMOVD$cmp $icc,$src,$dst" %}
- opcode(0x102);
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(int_conditional_double_move);
-%}
-
-instruct cmovDIu_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src) %{
- match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "FMOVD$cmp $icc,$src,$dst" %}
- opcode(0x102);
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(int_conditional_double_move);
-%}
-
-// Conditional move,
-instruct cmovDF_reg(cmpOpF cmp, flagsRegF fcc, regD dst, regD src) %{
- match(Set dst (CMoveD (Binary cmp fcc) (Binary dst src)));
- ins_cost(150);
- size(4);
- format %{ "FMOVD$cmp $fcc,$src,$dst" %}
- opcode(0x2);
- ins_encode( enc_cmovff_reg(cmp,fcc,dst,src) );
- ins_pipe(int_conditional_double_move);
-%}
-
-// Conditional move
-instruct cmovLP_reg(cmpOpP cmp, flagsRegP pcc, iRegL dst, iRegL src) %{
- match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $pcc,$src,$dst\t! long" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovLP_imm(cmpOpP cmp, flagsRegP pcc, iRegL dst, immI11 src) %{
- match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
- ins_cost(140);
- format %{ "MOV$cmp $pcc,$src,$dst\t! long" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::ptr_cc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovLI_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{
- match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst\t! long" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-
-instruct cmovLIu_reg(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src) %{
- match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "MOV$cmp $icc,$src,$dst\t! long" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) );
- ins_pipe(ialu_reg);
-%}
-
-
-instruct cmovLF_reg(cmpOpF cmp, flagsRegF fcc, iRegL dst, iRegL src) %{
- match(Set dst (CMoveL (Binary cmp fcc) (Binary dst src)));
- ins_cost(150);
-
- size(4);
- format %{ "MOV$cmp $fcc,$src,$dst\t! long" %}
- ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) );
- ins_pipe(ialu_reg);
-%}
-
-
-
-//----------OS and Locking Instructions----------------------------------------
-
-// This name is KNOWN by the ADLC and cannot be changed.
-// The ADLC forces a 'TypeRawPtr::BOTTOM' output type
-// for this guy.
-instruct tlsLoadP(g2RegP dst) %{
- match(Set dst (ThreadLocal));
-
- size(0);
- ins_cost(0);
- format %{ "# TLS is in G2" %}
- ins_encode( /*empty encoding*/ );
- ins_pipe(ialu_none);
-%}
-
-instruct checkCastPP( iRegP dst ) %{
- match(Set dst (CheckCastPP dst));
-
- size(0);
- format %{ "# checkcastPP of $dst" %}
- ins_encode( /*empty encoding*/ );
- ins_pipe(empty);
-%}
-
-
-instruct castPP( iRegP dst ) %{
- match(Set dst (CastPP dst));
- format %{ "# castPP of $dst" %}
- ins_encode( /*empty encoding*/ );
- ins_pipe(empty);
-%}
-
-instruct castII( iRegI dst ) %{
- match(Set dst (CastII dst));
- format %{ "# castII of $dst" %}
- ins_encode( /*empty encoding*/ );
- ins_cost(0);
- ins_pipe(empty);
-%}
-
-//----------Arithmetic Instructions--------------------------------------------
-// Addition Instructions
-// Register Addition
-instruct addI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (AddI src1 src2));
-
- size(4);
- format %{ "ADD $src1,$src2,$dst" %}
- ins_encode %{
- __ add($src1$$Register, $src2$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg_reg);
-%}
-
-// Immediate Addition
-instruct addI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{
- match(Set dst (AddI src1 src2));
-
- size(4);
- format %{ "ADD $src1,$src2,$dst" %}
- opcode(Assembler::add_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Pointer Register Addition
-instruct addP_reg_reg(iRegP dst, iRegP src1, iRegX src2) %{
- match(Set dst (AddP src1 src2));
-
- size(4);
- format %{ "ADD $src1,$src2,$dst" %}
- opcode(Assembler::add_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Pointer Immediate Addition
-instruct addP_reg_imm13(iRegP dst, iRegP src1, immX13 src2) %{
- match(Set dst (AddP src1 src2));
-
- size(4);
- format %{ "ADD $src1,$src2,$dst" %}
- opcode(Assembler::add_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Long Addition
-instruct addL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (AddL src1 src2));
-
- size(4);
- format %{ "ADD $src1,$src2,$dst\t! long" %}
- opcode(Assembler::add_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct addL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{
- match(Set dst (AddL src1 con));
-
- size(4);
- format %{ "ADD $src1,$con,$dst" %}
- opcode(Assembler::add_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, con, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-//----------Conditional_store--------------------------------------------------
-// Conditional-store of the updated heap-top.
-// Used during allocation of the shared heap.
-// Sets flags (EQ) on success. Implemented with a CASA on Sparc.
-
-// LoadP-locked. Same as a regular pointer load when used with a compare-swap
-instruct loadPLocked(iRegP dst, memory mem) %{
- match(Set dst (LoadPLocked mem));
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDX $mem,$dst\t! ptr" %}
- opcode(Assembler::ldx_op3, 0, REGP_OP);
- ins_encode( form3_mem_reg( mem, dst ) );
- ins_pipe(iload_mem);
-%}
-
-instruct storePConditional( iRegP heap_top_ptr, iRegP oldval, g3RegP newval, flagsRegP pcc ) %{
- match(Set pcc (StorePConditional heap_top_ptr (Binary oldval newval)));
- effect( KILL newval );
- format %{ "CASA [$heap_top_ptr],$oldval,R_G3\t! If $oldval==[$heap_top_ptr] Then store R_G3 into [$heap_top_ptr], set R_G3=[$heap_top_ptr] in any case\n\t"
- "CMP R_G3,$oldval\t\t! See if we made progress" %}
- ins_encode( enc_cas(heap_top_ptr,oldval,newval) );
- ins_pipe( long_memory_op );
-%}
-
-// Conditional-store of an int value.
-instruct storeIConditional( iRegP mem_ptr, iRegI oldval, g3RegI newval, flagsReg icc ) %{
- match(Set icc (StoreIConditional mem_ptr (Binary oldval newval)));
- effect( KILL newval );
- format %{ "CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr], set $newval=[$mem_ptr] in any case\n\t"
- "CMP $oldval,$newval\t\t! See if we made progress" %}
- ins_encode( enc_cas(mem_ptr,oldval,newval) );
- ins_pipe( long_memory_op );
-%}
-
-// Conditional-store of a long value.
-instruct storeLConditional( iRegP mem_ptr, iRegL oldval, g3RegL newval, flagsRegL xcc ) %{
- match(Set xcc (StoreLConditional mem_ptr (Binary oldval newval)));
- effect( KILL newval );
- format %{ "CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr], set $newval=[$mem_ptr] in any case\n\t"
- "CMP $oldval,$newval\t\t! See if we made progress" %}
- ins_encode( enc_cas(mem_ptr,oldval,newval) );
- ins_pipe( long_memory_op );
-%}
-
-// No flag versions for CompareAndSwap{P,I,L} because matcher can't match them
-
-instruct compareAndSwapL_bool(iRegP mem_ptr, iRegL oldval, iRegL newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
- predicate(VM_Version::supports_cx8());
- match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval)));
- match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr, KILL ccr, KILL tmp1);
- format %{
- "MOV $newval,O7\n\t"
- "CASXA [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t"
- "CMP $oldval,O7\t\t! See if we made progress\n\t"
- "MOV 1,$res\n\t"
- "MOVne xcc,R_G0,$res"
- %}
- ins_encode( enc_casx(mem_ptr, oldval, newval),
- enc_lflags_ne_to_boolean(res) );
- ins_pipe( long_memory_op );
-%}
-
-
-instruct compareAndSwapI_bool(iRegP mem_ptr, iRegI oldval, iRegI newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
- match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval)));
- match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr, KILL ccr, KILL tmp1);
- format %{
- "MOV $newval,O7\n\t"
- "CASA [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t"
- "CMP $oldval,O7\t\t! See if we made progress\n\t"
- "MOV 1,$res\n\t"
- "MOVne icc,R_G0,$res"
- %}
- ins_encode( enc_casi(mem_ptr, oldval, newval),
- enc_iflags_ne_to_boolean(res) );
- ins_pipe( long_memory_op );
-%}
-
-instruct compareAndSwapP_bool(iRegP mem_ptr, iRegP oldval, iRegP newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
- predicate(VM_Version::supports_cx8());
- match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval)));
- match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr, KILL ccr, KILL tmp1);
- format %{
- "MOV $newval,O7\n\t"
- "CASA_PTR [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t"
- "CMP $oldval,O7\t\t! See if we made progress\n\t"
- "MOV 1,$res\n\t"
- "MOVne xcc,R_G0,$res"
- %}
- ins_encode( enc_casx(mem_ptr, oldval, newval),
- enc_lflags_ne_to_boolean(res) );
- ins_pipe( long_memory_op );
-%}
-
-instruct compareAndSwapN_bool(iRegP mem_ptr, iRegN oldval, iRegN newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
- match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval)));
- match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr, KILL ccr, KILL tmp1);
- format %{
- "MOV $newval,O7\n\t"
- "CASA [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t"
- "CMP $oldval,O7\t\t! See if we made progress\n\t"
- "MOV 1,$res\n\t"
- "MOVne icc,R_G0,$res"
- %}
- ins_encode( enc_casi(mem_ptr, oldval, newval),
- enc_iflags_ne_to_boolean(res) );
- ins_pipe( long_memory_op );
-%}
-
-instruct compareAndExchangeI(iRegP mem_ptr, iRegI oldval, iRegI newval)
-%{
- match(Set newval (CompareAndExchangeI mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr );
-
- format %{
- "CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
- %}
- ins_encode( enc_casi_exch(mem_ptr, oldval, newval) );
- ins_pipe( long_memory_op );
-%}
-
-instruct compareAndExchangeL(iRegP mem_ptr, iRegL oldval, iRegL newval)
-%{
- match(Set newval (CompareAndExchangeL mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr );
-
- format %{
- "CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
- %}
- ins_encode( enc_casx_exch(mem_ptr, oldval, newval) );
- ins_pipe( long_memory_op );
-%}
-
-instruct compareAndExchangeP(iRegP mem_ptr, iRegP oldval, iRegP newval)
-%{
- match(Set newval (CompareAndExchangeP mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr );
-
- format %{
- "CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
- %}
- ins_encode( enc_casx_exch(mem_ptr, oldval, newval) );
- ins_pipe( long_memory_op );
-%}
-
-instruct compareAndExchangeN(iRegP mem_ptr, iRegN oldval, iRegN newval)
-%{
- match(Set newval (CompareAndExchangeN mem_ptr (Binary oldval newval)));
- effect( USE mem_ptr );
-
- format %{
- "CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
- %}
- ins_encode( enc_casi_exch(mem_ptr, oldval, newval) );
- ins_pipe( long_memory_op );
-%}
-
-instruct xchgI( memory mem, iRegI newval) %{
- match(Set newval (GetAndSetI mem newval));
- format %{ "SWAP [$mem],$newval" %}
- size(4);
- ins_encode %{
- __ swap($mem$$Address, $newval$$Register);
- %}
- ins_pipe( long_memory_op );
-%}
-
-
-instruct xchgN( memory mem, iRegN newval) %{
- match(Set newval (GetAndSetN mem newval));
- format %{ "SWAP [$mem],$newval" %}
- size(4);
- ins_encode %{
- __ swap($mem$$Address, $newval$$Register);
- %}
- ins_pipe( long_memory_op );
-%}
-
-//---------------------
-// Subtraction Instructions
-// Register Subtraction
-instruct subI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (SubI src1 src2));
-
- size(4);
- format %{ "SUB $src1,$src2,$dst" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Immediate Subtraction
-instruct subI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{
- match(Set dst (SubI src1 src2));
-
- size(4);
- format %{ "SUB $src1,$src2,$dst" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-instruct subI_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{
- match(Set dst (SubI zero src2));
-
- size(4);
- format %{ "NEG $src2,$dst" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( R_G0, src2, dst ) );
- ins_pipe(ialu_zero_reg);
-%}
-
-// Long subtraction
-instruct subL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (SubL src1 src2));
-
- size(4);
- format %{ "SUB $src1,$src2,$dst\t! long" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Immediate Subtraction
-instruct subL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{
- match(Set dst (SubL src1 con));
-
- size(4);
- format %{ "SUB $src1,$con,$dst\t! long" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, con, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Long negation
-instruct negL_reg_reg(iRegL dst, immL0 zero, iRegL src2) %{
- match(Set dst (SubL zero src2));
-
- size(4);
- format %{ "NEG $src2,$dst\t! long" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( R_G0, src2, dst ) );
- ins_pipe(ialu_zero_reg);
-%}
-
-// Multiplication Instructions
-// Integer Multiplication
-// Register Multiplication
-instruct mulI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (MulI src1 src2));
-
- size(4);
- format %{ "MULX $src1,$src2,$dst" %}
- opcode(Assembler::mulx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(imul_reg_reg);
-%}
-
-// Immediate Multiplication
-instruct mulI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{
- match(Set dst (MulI src1 src2));
-
- size(4);
- format %{ "MULX $src1,$src2,$dst" %}
- opcode(Assembler::mulx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(imul_reg_imm);
-%}
-
-instruct mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (MulL src1 src2));
- ins_cost(DEFAULT_COST * 5);
- size(4);
- format %{ "MULX $src1,$src2,$dst\t! long" %}
- opcode(Assembler::mulx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(mulL_reg_reg);
-%}
-
-// Immediate Multiplication
-instruct mulL_reg_imm13(iRegL dst, iRegL src1, immL13 src2) %{
- match(Set dst (MulL src1 src2));
- ins_cost(DEFAULT_COST * 5);
- size(4);
- format %{ "MULX $src1,$src2,$dst" %}
- opcode(Assembler::mulx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(mulL_reg_imm);
-%}
-
-// Integer Division
-// Register Division
-instruct divI_reg_reg(iRegI dst, iRegIsafe src1, iRegIsafe src2) %{
- match(Set dst (DivI src1 src2));
- ins_cost((2+71)*DEFAULT_COST);
-
- format %{ "SRA $src2,0,$src2\n\t"
- "SRA $src1,0,$src1\n\t"
- "SDIVX $src1,$src2,$dst" %}
- ins_encode( idiv_reg( src1, src2, dst ) );
- ins_pipe(sdiv_reg_reg);
-%}
-
-// Immediate Division
-instruct divI_reg_imm13(iRegI dst, iRegIsafe src1, immI13 src2) %{
- match(Set dst (DivI src1 src2));
- ins_cost((2+71)*DEFAULT_COST);
-
- format %{ "SRA $src1,0,$src1\n\t"
- "SDIVX $src1,$src2,$dst" %}
- ins_encode( idiv_imm( src1, src2, dst ) );
- ins_pipe(sdiv_reg_imm);
-%}
-
-//----------Div-By-10-Expansion------------------------------------------------
-// Extract hi bits of a 32x32->64 bit multiply.
-// Expand rule only, not matched
-instruct mul_hi(iRegIsafe dst, iRegIsafe src1, iRegIsafe src2 ) %{
- effect( DEF dst, USE src1, USE src2 );
- format %{ "MULX $src1,$src2,$dst\t! Used in div-by-10\n\t"
- "SRLX $dst,#32,$dst\t\t! Extract only hi word of result" %}
- ins_encode( enc_mul_hi(dst,src1,src2));
- ins_pipe(sdiv_reg_reg);
-%}
-
-// Magic constant, reciprocal of 10
-instruct loadConI_x66666667(iRegIsafe dst) %{
- effect( DEF dst );
-
- size(8);
- format %{ "SET 0x66666667,$dst\t! Used in div-by-10" %}
- ins_encode( Set32(0x66666667, dst) );
- ins_pipe(ialu_hi_lo_reg);
-%}
-
-// Register Shift Right Arithmetic Long by 32-63
-instruct sra_31( iRegI dst, iRegI src ) %{
- effect( DEF dst, USE src );
- format %{ "SRA $src,31,$dst\t! Used in div-by-10" %}
- ins_encode( form3_rs1_rd_copysign_hi(src,dst) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Arithmetic Shift Right by 8-bit immediate
-instruct sra_reg_2( iRegI dst, iRegI src ) %{
- effect( DEF dst, USE src );
- format %{ "SRA $src,2,$dst\t! Used in div-by-10" %}
- opcode(Assembler::sra_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src, 0x2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Integer DIV with 10
-instruct divI_10( iRegI dst, iRegIsafe src, immI10 div ) %{
- match(Set dst (DivI src div));
- ins_cost((6+6)*DEFAULT_COST);
- expand %{
- iRegIsafe tmp1; // Killed temps;
- iRegIsafe tmp2; // Killed temps;
- iRegI tmp3; // Killed temps;
- iRegI tmp4; // Killed temps;
- loadConI_x66666667( tmp1 ); // SET 0x66666667 -> tmp1
- mul_hi( tmp2, src, tmp1 ); // MUL hibits(src * tmp1) -> tmp2
- sra_31( tmp3, src ); // SRA src,31 -> tmp3
- sra_reg_2( tmp4, tmp2 ); // SRA tmp2,2 -> tmp4
- subI_reg_reg( dst,tmp4,tmp3); // SUB tmp4 - tmp3 -> dst
- %}
-%}
-
-// Register Long Division
-instruct divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (DivL src1 src2));
- ins_cost(DEFAULT_COST*71);
- size(4);
- format %{ "SDIVX $src1,$src2,$dst\t! long" %}
- opcode(Assembler::sdivx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(divL_reg_reg);
-%}
-
-// Register Long Division
-instruct divL_reg_imm13(iRegL dst, iRegL src1, immL13 src2) %{
- match(Set dst (DivL src1 src2));
- ins_cost(DEFAULT_COST*71);
- size(4);
- format %{ "SDIVX $src1,$src2,$dst\t! long" %}
- opcode(Assembler::sdivx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(divL_reg_imm);
-%}
-
-// Integer Remainder
-// Register Remainder
-instruct modI_reg_reg(iRegI dst, iRegIsafe src1, iRegIsafe src2, o7RegP temp, flagsReg ccr ) %{
- match(Set dst (ModI src1 src2));
- effect( KILL ccr, KILL temp);
-
- format %{ "SREM $src1,$src2,$dst" %}
- ins_encode( irem_reg(src1, src2, dst, temp) );
- ins_pipe(sdiv_reg_reg);
-%}
-
-// Immediate Remainder
-instruct modI_reg_imm13(iRegI dst, iRegIsafe src1, immI13 src2, o7RegP temp, flagsReg ccr ) %{
- match(Set dst (ModI src1 src2));
- effect( KILL ccr, KILL temp);
-
- format %{ "SREM $src1,$src2,$dst" %}
- ins_encode( irem_imm(src1, src2, dst, temp) );
- ins_pipe(sdiv_reg_imm);
-%}
-
-// Register Long Remainder
-instruct divL_reg_reg_1(iRegL dst, iRegL src1, iRegL src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "SDIVX $src1,$src2,$dst\t! long" %}
- opcode(Assembler::sdivx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(divL_reg_reg);
-%}
-
-// Register Long Division
-instruct divL_reg_imm13_1(iRegL dst, iRegL src1, immL13 src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "SDIVX $src1,$src2,$dst\t! long" %}
- opcode(Assembler::sdivx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(divL_reg_imm);
-%}
-
-instruct mulL_reg_reg_1(iRegL dst, iRegL src1, iRegL src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "MULX $src1,$src2,$dst\t! long" %}
- opcode(Assembler::mulx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(mulL_reg_reg);
-%}
-
-// Immediate Multiplication
-instruct mulL_reg_imm13_1(iRegL dst, iRegL src1, immL13 src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "MULX $src1,$src2,$dst" %}
- opcode(Assembler::mulx_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(mulL_reg_imm);
-%}
-
-instruct subL_reg_reg_1(iRegL dst, iRegL src1, iRegL src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "SUB $src1,$src2,$dst\t! long" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct subL_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "SUB $src1,$src2,$dst\t! long" %}
- opcode(Assembler::sub_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Register Long Remainder
-instruct modL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (ModL src1 src2));
- ins_cost(DEFAULT_COST*(71 + 6 + 1));
- expand %{
- iRegL tmp1;
- iRegL tmp2;
- divL_reg_reg_1(tmp1, src1, src2);
- mulL_reg_reg_1(tmp2, tmp1, src2);
- subL_reg_reg_1(dst, src1, tmp2);
- %}
-%}
-
-// Register Long Remainder
-instruct modL_reg_imm13(iRegL dst, iRegL src1, immL13 src2) %{
- match(Set dst (ModL src1 src2));
- ins_cost(DEFAULT_COST*(71 + 6 + 1));
- expand %{
- iRegL tmp1;
- iRegL tmp2;
- divL_reg_imm13_1(tmp1, src1, src2);
- mulL_reg_imm13_1(tmp2, tmp1, src2);
- subL_reg_reg_2 (dst, src1, tmp2);
- %}
-%}
-
-// Integer Shift Instructions
-// Register Shift Left
-instruct shlI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (LShiftI src1 src2));
-
- size(4);
- format %{ "SLL $src1,$src2,$dst" %}
- opcode(Assembler::sll_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Register Shift Left Immediate
-instruct shlI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
- match(Set dst (LShiftI src1 src2));
-
- size(4);
- format %{ "SLL $src1,$src2,$dst" %}
- opcode(Assembler::sll_op3, Assembler::arith_op);
- ins_encode( form3_rs1_imm5_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Shift Left
-instruct shlL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
- match(Set dst (LShiftL src1 src2));
-
- size(4);
- format %{ "SLLX $src1,$src2,$dst" %}
- opcode(Assembler::sllx_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Register Shift Left Immediate
-instruct shlL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{
- match(Set dst (LShiftL src1 src2));
-
- size(4);
- format %{ "SLLX $src1,$src2,$dst" %}
- opcode(Assembler::sllx_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Arithmetic Shift Right
-instruct sarI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (RShiftI src1 src2));
- size(4);
- format %{ "SRA $src1,$src2,$dst" %}
- opcode(Assembler::sra_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Register Arithmetic Shift Right Immediate
-instruct sarI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
- match(Set dst (RShiftI src1 src2));
-
- size(4);
- format %{ "SRA $src1,$src2,$dst" %}
- opcode(Assembler::sra_op3, Assembler::arith_op);
- ins_encode( form3_rs1_imm5_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Shift Right Arithmatic Long
-instruct sarL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
- match(Set dst (RShiftL src1 src2));
-
- size(4);
- format %{ "SRAX $src1,$src2,$dst" %}
- opcode(Assembler::srax_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Register Shift Left Immediate
-instruct sarL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{
- match(Set dst (RShiftL src1 src2));
-
- size(4);
- format %{ "SRAX $src1,$src2,$dst" %}
- opcode(Assembler::srax_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Shift Right
-instruct shrI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (URShiftI src1 src2));
-
- size(4);
- format %{ "SRL $src1,$src2,$dst" %}
- opcode(Assembler::srl_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Register Shift Right Immediate
-instruct shrI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
- match(Set dst (URShiftI src1 src2));
-
- size(4);
- format %{ "SRL $src1,$src2,$dst" %}
- opcode(Assembler::srl_op3, Assembler::arith_op);
- ins_encode( form3_rs1_imm5_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Shift Right
-instruct shrL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
- match(Set dst (URShiftL src1 src2));
-
- size(4);
- format %{ "SRLX $src1,$src2,$dst" %}
- opcode(Assembler::srlx_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Register Shift Right Immediate
-instruct shrL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{
- match(Set dst (URShiftL src1 src2));
-
- size(4);
- format %{ "SRLX $src1,$src2,$dst" %}
- opcode(Assembler::srlx_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Shift Right Immediate with a CastP2X
-instruct shrP_reg_imm6(iRegL dst, iRegP src1, immU6 src2) %{
- match(Set dst (URShiftL (CastP2X src1) src2));
- size(4);
- format %{ "SRLX $src1,$src2,$dst\t! Cast ptr $src1 to long and shift" %}
- opcode(Assembler::srlx_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-
-//----------Floating Point Arithmetic Instructions-----------------------------
-
-// Add float single precision
-instruct addF_reg_reg(regF dst, regF src1, regF src2) %{
- match(Set dst (AddF src1 src2));
-
- size(4);
- format %{ "FADDS $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fadds_opf);
- ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst));
- ins_pipe(faddF_reg_reg);
-%}
-
-// Add float double precision
-instruct addD_reg_reg(regD dst, regD src1, regD src2) %{
- match(Set dst (AddD src1 src2));
-
- size(4);
- format %{ "FADDD $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::faddd_opf);
- ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst));
- ins_pipe(faddD_reg_reg);
-%}
-
-// Sub float single precision
-instruct subF_reg_reg(regF dst, regF src1, regF src2) %{
- match(Set dst (SubF src1 src2));
-
- size(4);
- format %{ "FSUBS $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fsubs_opf);
- ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst));
- ins_pipe(faddF_reg_reg);
-%}
-
-// Sub float double precision
-instruct subD_reg_reg(regD dst, regD src1, regD src2) %{
- match(Set dst (SubD src1 src2));
-
- size(4);
- format %{ "FSUBD $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fsubd_opf);
- ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst));
- ins_pipe(faddD_reg_reg);
-%}
-
-// Mul float single precision
-instruct mulF_reg_reg(regF dst, regF src1, regF src2) %{
- match(Set dst (MulF src1 src2));
-
- size(4);
- format %{ "FMULS $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmuls_opf);
- ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst));
- ins_pipe(fmulF_reg_reg);
-%}
-
-// Mul float double precision
-instruct mulD_reg_reg(regD dst, regD src1, regD src2) %{
- match(Set dst (MulD src1 src2));
-
- size(4);
- format %{ "FMULD $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmuld_opf);
- ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst));
- ins_pipe(fmulD_reg_reg);
-%}
-
-// Div float single precision
-instruct divF_reg_reg(regF dst, regF src1, regF src2) %{
- match(Set dst (DivF src1 src2));
-
- size(4);
- format %{ "FDIVS $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdivs_opf);
- ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst));
- ins_pipe(fdivF_reg_reg);
-%}
-
-// Div float double precision
-instruct divD_reg_reg(regD dst, regD src1, regD src2) %{
- match(Set dst (DivD src1 src2));
-
- size(4);
- format %{ "FDIVD $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdivd_opf);
- ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst));
- ins_pipe(fdivD_reg_reg);
-%}
-
-// Absolute float double precision
-instruct absD_reg(regD dst, regD src) %{
- match(Set dst (AbsD src));
-
- format %{ "FABSd $src,$dst" %}
- ins_encode(fabsd(dst, src));
- ins_pipe(faddD_reg);
-%}
-
-// Absolute float single precision
-instruct absF_reg(regF dst, regF src) %{
- match(Set dst (AbsF src));
-
- format %{ "FABSs $src,$dst" %}
- ins_encode(fabss(dst, src));
- ins_pipe(faddF_reg);
-%}
-
-instruct negF_reg(regF dst, regF src) %{
- match(Set dst (NegF src));
-
- size(4);
- format %{ "FNEGs $src,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fnegs_opf);
- ins_encode(form3_opf_rs2F_rdF(src, dst));
- ins_pipe(faddF_reg);
-%}
-
-instruct negD_reg(regD dst, regD src) %{
- match(Set dst (NegD src));
-
- format %{ "FNEGd $src,$dst" %}
- ins_encode(fnegd(dst, src));
- ins_pipe(faddD_reg);
-%}
-
-// Sqrt float double precision
-instruct sqrtF_reg_reg(regF dst, regF src) %{
- match(Set dst (ConvD2F (SqrtD (ConvF2D src))));
-
- size(4);
- format %{ "FSQRTS $src,$dst" %}
- ins_encode(fsqrts(dst, src));
- ins_pipe(fdivF_reg_reg);
-%}
-
-// Sqrt float double precision
-instruct sqrtD_reg_reg(regD dst, regD src) %{
- match(Set dst (SqrtD src));
-
- size(4);
- format %{ "FSQRTD $src,$dst" %}
- ins_encode(fsqrtd(dst, src));
- ins_pipe(fdivD_reg_reg);
-%}
-
-// Single/Double precision fused floating-point multiply-add (d = a * b + c).
-instruct fmaF_regx4(regF dst, regF a, regF b, regF c) %{
- predicate(UseFMA);
- match(Set dst (FmaF c (Binary a b)));
- format %{ "fmadds $a,$b,$c,$dst\t# $dst = $a * $b + $c" %}
- ins_encode(fmadds(dst, a, b, c));
- ins_pipe(fmaF_regx4);
-%}
-
-instruct fmaD_regx4(regD dst, regD a, regD b, regD c) %{
- predicate(UseFMA);
- match(Set dst (FmaD c (Binary a b)));
- format %{ "fmaddd $a,$b,$c,$dst\t# $dst = $a * $b + $c" %}
- ins_encode(fmaddd(dst, a, b, c));
- ins_pipe(fmaD_regx4);
-%}
-
-// Additional patterns matching complement versions that we can map directly to
-// variants of the fused multiply-add instructions.
-
-// Single/Double precision fused floating-point multiply-sub (d = a * b - c)
-instruct fmsubF_regx4(regF dst, regF a, regF b, regF c) %{
- predicate(UseFMA);
- match(Set dst (FmaF (NegF c) (Binary a b)));
- format %{ "fmsubs $a,$b,$c,$dst\t# $dst = $a * $b - $c" %}
- ins_encode(fmsubs(dst, a, b, c));
- ins_pipe(fmaF_regx4);
-%}
-
-instruct fmsubD_regx4(regD dst, regD a, regD b, regD c) %{
- predicate(UseFMA);
- match(Set dst (FmaD (NegD c) (Binary a b)));
- format %{ "fmsubd $a,$b,$c,$dst\t# $dst = $a * $b - $c" %}
- ins_encode(fmsubd(dst, a, b, c));
- ins_pipe(fmaD_regx4);
-%}
-
-// Single/Double precision fused floating-point neg. multiply-add,
-// d = -1 * a * b - c = -(a * b + c)
-instruct fnmaddF_regx4(regF dst, regF a, regF b, regF c) %{
- predicate(UseFMA);
- match(Set dst (FmaF (NegF c) (Binary (NegF a) b)));
- match(Set dst (FmaF (NegF c) (Binary a (NegF b))));
- format %{ "fnmadds $a,$b,$c,$dst\t# $dst = -($a * $b + $c)" %}
- ins_encode(fnmadds(dst, a, b, c));
- ins_pipe(fmaF_regx4);
-%}
-
-instruct fnmaddD_regx4(regD dst, regD a, regD b, regD c) %{
- predicate(UseFMA);
- match(Set dst (FmaD (NegD c) (Binary (NegD a) b)));
- match(Set dst (FmaD (NegD c) (Binary a (NegD b))));
- format %{ "fnmaddd $a,$b,$c,$dst\t# $dst = -($a * $b + $c)" %}
- ins_encode(fnmaddd(dst, a, b, c));
- ins_pipe(fmaD_regx4);
-%}
-
-// Single/Double precision fused floating-point neg. multiply-sub,
-// d = -1 * a * b + c = -(a * b - c)
-instruct fnmsubF_regx4(regF dst, regF a, regF b, regF c) %{
- predicate(UseFMA);
- match(Set dst (FmaF c (Binary (NegF a) b)));
- match(Set dst (FmaF c (Binary a (NegF b))));
- format %{ "fnmsubs $a,$b,$c,$dst\t# $dst = -($a * $b - $c)" %}
- ins_encode(fnmsubs(dst, a, b, c));
- ins_pipe(fmaF_regx4);
-%}
-
-instruct fnmsubD_regx4(regD dst, regD a, regD b, regD c) %{
- predicate(UseFMA);
- match(Set dst (FmaD c (Binary (NegD a) b)));
- match(Set dst (FmaD c (Binary a (NegD b))));
- format %{ "fnmsubd $a,$b,$c,$dst\t# $dst = -($a * $b - $c)" %}
- ins_encode(fnmsubd(dst, a, b, c));
- ins_pipe(fmaD_regx4);
-%}
-
-//----------Logical Instructions-----------------------------------------------
-// And Instructions
-// Register And
-instruct andI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (AndI src1 src2));
-
- size(4);
- format %{ "AND $src1,$src2,$dst" %}
- opcode(Assembler::and_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Immediate And
-instruct andI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{
- match(Set dst (AndI src1 src2));
-
- size(4);
- format %{ "AND $src1,$src2,$dst" %}
- opcode(Assembler::and_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register And Long
-instruct andL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (AndL src1 src2));
-
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "AND $src1,$src2,$dst\t! long" %}
- opcode(Assembler::and_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct andL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{
- match(Set dst (AndL src1 con));
-
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "AND $src1,$con,$dst\t! long" %}
- opcode(Assembler::and_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, con, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Or Instructions
-// Register Or
-instruct orI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (OrI src1 src2));
-
- size(4);
- format %{ "OR $src1,$src2,$dst" %}
- opcode(Assembler::or_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Immediate Or
-instruct orI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{
- match(Set dst (OrI src1 src2));
-
- size(4);
- format %{ "OR $src1,$src2,$dst" %}
- opcode(Assembler::or_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Or Long
-instruct orL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (OrL src1 src2));
-
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "OR $src1,$src2,$dst\t! long" %}
- opcode(Assembler::or_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct orL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{
- match(Set dst (OrL src1 con));
- ins_cost(DEFAULT_COST*2);
-
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "OR $src1,$con,$dst\t! long" %}
- opcode(Assembler::or_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, con, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-instruct orL_reg_castP2X(iRegL dst, iRegL src1, sp_ptr_RegP src2) %{
- match(Set dst (OrL src1 (CastP2X src2)));
-
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "OR $src1,$src2,$dst\t! long" %}
- opcode(Assembler::or_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Xor Instructions
-// Register Xor
-instruct xorI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
- match(Set dst (XorI src1 src2));
-
- size(4);
- format %{ "XOR $src1,$src2,$dst" %}
- opcode(Assembler::xor_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Immediate Xor
-instruct xorI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{
- match(Set dst (XorI src1 src2));
-
- size(4);
- format %{ "XOR $src1,$src2,$dst" %}
- opcode(Assembler::xor_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-// Register Xor Long
-instruct xorL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
- match(Set dst (XorL src1 src2));
-
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "XOR $src1,$src2,$dst\t! long" %}
- opcode(Assembler::xor_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct xorL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{
- match(Set dst (XorL src1 con));
-
- ins_cost(DEFAULT_COST);
- size(4);
- format %{ "XOR $src1,$con,$dst\t! long" %}
- opcode(Assembler::xor_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( src1, con, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-//----------Convert to Boolean-------------------------------------------------
-// Nice hack for 32-bit tests but doesn't work for
-// 64-bit pointers.
-instruct convI2B( iRegI dst, iRegI src, flagsReg ccr ) %{
- match(Set dst (Conv2B src));
- effect( KILL ccr );
- ins_cost(DEFAULT_COST*2);
- format %{ "CMP R_G0,$src\n\t"
- "ADDX R_G0,0,$dst" %}
- ins_encode( enc_to_bool( src, dst ) );
- ins_pipe(ialu_reg_ialu);
-%}
-
-instruct convP2B( iRegI dst, iRegP src ) %{
- match(Set dst (Conv2B src));
- ins_cost(DEFAULT_COST*2);
- format %{ "MOV $src,$dst\n\t"
- "MOVRNZ $src,1,$dst" %}
- ins_encode( form3_g0_rs2_rd_move( src, dst ), enc_convP2B( dst, src ) );
- ins_pipe(ialu_clr_and_mover);
-%}
-
-instruct cmpLTMask0( iRegI dst, iRegI src, immI0 zero, flagsReg ccr ) %{
- match(Set dst (CmpLTMask src zero));
- effect(KILL ccr);
- size(4);
- format %{ "SRA $src,#31,$dst\t# cmpLTMask0" %}
- ins_encode %{
- __ sra($src$$Register, 31, $dst$$Register);
- %}
- ins_pipe(ialu_reg_imm);
-%}
-
-instruct cmpLTMask_reg_reg( iRegI dst, iRegI p, iRegI q, flagsReg ccr ) %{
- match(Set dst (CmpLTMask p q));
- effect( KILL ccr );
- ins_cost(DEFAULT_COST*4);
- format %{ "CMP $p,$q\n\t"
- "MOV #0,$dst\n\t"
- "BLT,a .+8\n\t"
- "MOV #-1,$dst" %}
- ins_encode( enc_ltmask(p,q,dst) );
- ins_pipe(ialu_reg_reg_ialu);
-%}
-
-instruct cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, iRegI tmp, flagsReg ccr ) %{
- match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
- effect(KILL ccr, TEMP tmp);
- ins_cost(DEFAULT_COST*3);
-
- format %{ "SUBcc $p,$q,$p\t! p' = p-q\n\t"
- "ADD $p,$y,$tmp\t! g3=p-q+y\n\t"
- "MOVlt $tmp,$p\t! p' < 0 ? p'+y : p'" %}
- ins_encode(enc_cadd_cmpLTMask(p, q, y, tmp));
- ins_pipe(cadd_cmpltmask);
-%}
-
-instruct and_cmpLTMask(iRegI p, iRegI q, iRegI y, flagsReg ccr) %{
- match(Set p (AndI (CmpLTMask p q) y));
- effect(KILL ccr);
- ins_cost(DEFAULT_COST*3);
-
- format %{ "CMP $p,$q\n\t"
- "MOV $y,$p\n\t"
- "MOVge G0,$p" %}
- ins_encode %{
- __ cmp($p$$Register, $q$$Register);
- __ mov($y$$Register, $p$$Register);
- __ movcc(Assembler::greaterEqual, false, Assembler::icc, G0, $p$$Register);
- %}
- ins_pipe(ialu_reg_reg_ialu);
-%}
-
-//-----------------------------------------------------------------
-// Direct raw moves between float and general registers using VIS3.
-
-// ins_pipe(faddF_reg);
-instruct MoveF2I_reg_reg(iRegI dst, regF src) %{
- predicate(UseVIS >= 3);
- match(Set dst (MoveF2I src));
-
- format %{ "MOVSTOUW $src,$dst\t! MoveF2I" %}
- ins_encode %{
- __ movstouw($src$$FloatRegister, $dst$$Register);
- %}
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct MoveI2F_reg_reg(regF dst, iRegI src) %{
- predicate(UseVIS >= 3);
- match(Set dst (MoveI2F src));
-
- format %{ "MOVWTOS $src,$dst\t! MoveI2F" %}
- ins_encode %{
- __ movwtos($src$$Register, $dst$$FloatRegister);
- %}
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct MoveD2L_reg_reg(iRegL dst, regD src) %{
- predicate(UseVIS >= 3);
- match(Set dst (MoveD2L src));
-
- format %{ "MOVDTOX $src,$dst\t! MoveD2L" %}
- ins_encode %{
- __ movdtox(as_DoubleFloatRegister($src$$reg), $dst$$Register);
- %}
- ins_pipe(ialu_reg_reg);
-%}
-
-instruct MoveL2D_reg_reg(regD dst, iRegL src) %{
- predicate(UseVIS >= 3);
- match(Set dst (MoveL2D src));
-
- format %{ "MOVXTOD $src,$dst\t! MoveL2D" %}
- ins_encode %{
- __ movxtod($src$$Register, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(ialu_reg_reg);
-%}
-
-
-// Raw moves between float and general registers using stack.
-
-instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{
- match(Set dst (MoveF2I src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDUW $src,$dst\t! MoveF2I" %}
- opcode(Assembler::lduw_op3);
- ins_encode(simple_form3_mem_reg( src, dst ) );
- ins_pipe(iload_mem);
-%}
-
-instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{
- match(Set dst (MoveI2F src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDF $src,$dst\t! MoveI2F" %}
- opcode(Assembler::ldf_op3);
- ins_encode(simple_form3_mem_reg(src, dst));
- ins_pipe(floadF_stk);
-%}
-
-instruct MoveD2L_stack_reg(iRegL dst, stackSlotD src) %{
- match(Set dst (MoveD2L src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDX $src,$dst\t! MoveD2L" %}
- opcode(Assembler::ldx_op3);
- ins_encode(simple_form3_mem_reg( src, dst ) );
- ins_pipe(iload_mem);
-%}
-
-instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{
- match(Set dst (MoveL2D src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "LDDF $src,$dst\t! MoveL2D" %}
- opcode(Assembler::lddf_op3);
- ins_encode(simple_form3_mem_reg(src, dst));
- ins_pipe(floadD_stk);
-%}
-
-instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{
- match(Set dst (MoveF2I src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STF $src,$dst\t! MoveF2I" %}
- opcode(Assembler::stf_op3);
- ins_encode(simple_form3_mem_reg(dst, src));
- ins_pipe(fstoreF_stk_reg);
-%}
-
-instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{
- match(Set dst (MoveI2F src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STW $src,$dst\t! MoveI2F" %}
- opcode(Assembler::stw_op3);
- ins_encode(simple_form3_mem_reg( dst, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{
- match(Set dst (MoveD2L src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STDF $src,$dst\t! MoveD2L" %}
- opcode(Assembler::stdf_op3);
- ins_encode(simple_form3_mem_reg(dst, src));
- ins_pipe(fstoreD_stk_reg);
-%}
-
-instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{
- match(Set dst (MoveL2D src));
- effect(DEF dst, USE src);
- ins_cost(MEMORY_REF_COST);
-
- format %{ "STX $src,$dst\t! MoveL2D" %}
- opcode(Assembler::stx_op3);
- ins_encode(simple_form3_mem_reg( dst, src ) );
- ins_pipe(istore_mem_reg);
-%}
-
-
-//----------Arithmetic Conversion Instructions---------------------------------
-// The conversions operations are all Alpha sorted. Please keep it that way!
-
-instruct convD2F_reg(regF dst, regD src) %{
- match(Set dst (ConvD2F src));
- size(4);
- format %{ "FDTOS $src,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdtos_opf);
- ins_encode(form3_opf_rs2D_rdF(src, dst));
- ins_pipe(fcvtD2F);
-%}
-
-
-// Convert a double to an int in a float register.
-// If the double is a NAN, stuff a zero in instead.
-instruct convD2I_helper(regF dst, regD src, flagsRegF0 fcc0) %{
- effect(DEF dst, USE src, KILL fcc0);
- format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t"
- "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
- "FDTOI $src,$dst\t! convert in delay slot\n\t"
- "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t"
- "FSUBs $dst,$dst,$dst\t! cleared only if nan\n"
- "skip:" %}
- ins_encode(form_d2i_helper(src,dst));
- ins_pipe(fcvtD2I);
-%}
-
-instruct convD2I_stk(stackSlotI dst, regD src) %{
- match(Set dst (ConvD2I src));
- ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
- expand %{
- regF tmp;
- convD2I_helper(tmp, src);
- regF_to_stkI(dst, tmp);
- %}
-%}
-
-instruct convD2I_reg(iRegI dst, regD src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvD2I src));
- ins_cost(DEFAULT_COST*2 + BRANCH_COST);
- expand %{
- regF tmp;
- convD2I_helper(tmp, src);
- MoveF2I_reg_reg(dst, tmp);
- %}
-%}
-
-
-// Convert a double to a long in a double register.
-// If the double is a NAN, stuff a zero in instead.
-instruct convD2L_helper(regD dst, regD src, flagsRegF0 fcc0) %{
- effect(DEF dst, USE src, KILL fcc0);
- format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t"
- "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
- "FDTOX $src,$dst\t! convert in delay slot\n\t"
- "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t"
- "FSUBd $dst,$dst,$dst\t! cleared only if nan\n"
- "skip:" %}
- ins_encode(form_d2l_helper(src,dst));
- ins_pipe(fcvtD2L);
-%}
-
-instruct convD2L_stk(stackSlotL dst, regD src) %{
- match(Set dst (ConvD2L src));
- ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
- expand %{
- regD tmp;
- convD2L_helper(tmp, src);
- regD_to_stkL(dst, tmp);
- %}
-%}
-
-instruct convD2L_reg(iRegL dst, regD src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvD2L src));
- ins_cost(DEFAULT_COST*2 + BRANCH_COST);
- expand %{
- regD tmp;
- convD2L_helper(tmp, src);
- MoveD2L_reg_reg(dst, tmp);
- %}
-%}
-
-
-instruct convF2D_reg(regD dst, regF src) %{
- match(Set dst (ConvF2D src));
- format %{ "FSTOD $src,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fstod_opf);
- ins_encode(form3_opf_rs2F_rdD(src, dst));
- ins_pipe(fcvtF2D);
-%}
-
-
-// Convert a float to an int in a float register.
-// If the float is a NAN, stuff a zero in instead.
-instruct convF2I_helper(regF dst, regF src, flagsRegF0 fcc0) %{
- effect(DEF dst, USE src, KILL fcc0);
- format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t"
- "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
- "FSTOI $src,$dst\t! convert in delay slot\n\t"
- "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t"
- "FSUBs $dst,$dst,$dst\t! cleared only if nan\n"
- "skip:" %}
- ins_encode(form_f2i_helper(src,dst));
- ins_pipe(fcvtF2I);
-%}
-
-instruct convF2I_stk(stackSlotI dst, regF src) %{
- match(Set dst (ConvF2I src));
- ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
- expand %{
- regF tmp;
- convF2I_helper(tmp, src);
- regF_to_stkI(dst, tmp);
- %}
-%}
-
-instruct convF2I_reg(iRegI dst, regF src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvF2I src));
- ins_cost(DEFAULT_COST*2 + BRANCH_COST);
- expand %{
- regF tmp;
- convF2I_helper(tmp, src);
- MoveF2I_reg_reg(dst, tmp);
- %}
-%}
-
-
-// Convert a float to a long in a float register.
-// If the float is a NAN, stuff a zero in instead.
-instruct convF2L_helper(regD dst, regF src, flagsRegF0 fcc0) %{
- effect(DEF dst, USE src, KILL fcc0);
- format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t"
- "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
- "FSTOX $src,$dst\t! convert in delay slot\n\t"
- "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t"
- "FSUBd $dst,$dst,$dst\t! cleared only if nan\n"
- "skip:" %}
- ins_encode(form_f2l_helper(src,dst));
- ins_pipe(fcvtF2L);
-%}
-
-instruct convF2L_stk(stackSlotL dst, regF src) %{
- match(Set dst (ConvF2L src));
- ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
- expand %{
- regD tmp;
- convF2L_helper(tmp, src);
- regD_to_stkL(dst, tmp);
- %}
-%}
-
-instruct convF2L_reg(iRegL dst, regF src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvF2L src));
- ins_cost(DEFAULT_COST*2 + BRANCH_COST);
- expand %{
- regD tmp;
- convF2L_helper(tmp, src);
- MoveD2L_reg_reg(dst, tmp);
- %}
-%}
-
-
-instruct convI2D_helper(regD dst, regF tmp) %{
- effect(USE tmp, DEF dst);
- format %{ "FITOD $tmp,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf);
- ins_encode(form3_opf_rs2F_rdD(tmp, dst));
- ins_pipe(fcvtI2D);
-%}
-
-instruct convI2D_stk(stackSlotI src, regD dst) %{
- match(Set dst (ConvI2D src));
- ins_cost(DEFAULT_COST + MEMORY_REF_COST);
- expand %{
- regF tmp;
- stkI_to_regF(tmp, src);
- convI2D_helper(dst, tmp);
- %}
-%}
-
-instruct convI2D_reg(regD_low dst, iRegI src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvI2D src));
- expand %{
- regF tmp;
- MoveI2F_reg_reg(tmp, src);
- convI2D_helper(dst, tmp);
- %}
-%}
-
-instruct convI2D_mem(regD_low dst, memory mem) %{
- match(Set dst (ConvI2D (LoadI mem)));
- ins_cost(DEFAULT_COST + MEMORY_REF_COST);
- format %{ "LDF $mem,$dst\n\t"
- "FITOD $dst,$dst" %}
- opcode(Assembler::ldf_op3, Assembler::fitod_opf);
- ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst));
- ins_pipe(floadF_mem);
-%}
-
-
-instruct convI2F_helper(regF dst, regF tmp) %{
- effect(DEF dst, USE tmp);
- format %{ "FITOS $tmp,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitos_opf);
- ins_encode(form3_opf_rs2F_rdF(tmp, dst));
- ins_pipe(fcvtI2F);
-%}
-
-instruct convI2F_stk(regF dst, stackSlotI src) %{
- match(Set dst (ConvI2F src));
- ins_cost(DEFAULT_COST + MEMORY_REF_COST);
- expand %{
- regF tmp;
- stkI_to_regF(tmp,src);
- convI2F_helper(dst, tmp);
- %}
-%}
-
-instruct convI2F_reg(regF dst, iRegI src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvI2F src));
- ins_cost(DEFAULT_COST);
- expand %{
- regF tmp;
- MoveI2F_reg_reg(tmp, src);
- convI2F_helper(dst, tmp);
- %}
-%}
-
-instruct convI2F_mem( regF dst, memory mem ) %{
- match(Set dst (ConvI2F (LoadI mem)));
- ins_cost(DEFAULT_COST + MEMORY_REF_COST);
- format %{ "LDF $mem,$dst\n\t"
- "FITOS $dst,$dst" %}
- opcode(Assembler::ldf_op3, Assembler::fitos_opf);
- ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst));
- ins_pipe(floadF_mem);
-%}
-
-
-instruct convI2L_reg(iRegL dst, iRegI src) %{
- match(Set dst (ConvI2L src));
- size(4);
- format %{ "SRA $src,0,$dst\t! int->long" %}
- opcode(Assembler::sra_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Zero-extend convert int to long
-instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{
- match(Set dst (AndL (ConvI2L src) mask) );
- size(4);
- format %{ "SRL $src,0,$dst\t! zero-extend int to long" %}
- opcode(Assembler::srl_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-// Zero-extend long
-instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{
- match(Set dst (AndL src mask) );
- size(4);
- format %{ "SRL $src,0,$dst\t! zero-extend long" %}
- opcode(Assembler::srl_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
- ins_pipe(ialu_reg_reg);
-%}
-
-
-//-----------
-// Long to Double conversion using V8 opcodes.
-// Still useful because cheetah traps and becomes
-// amazingly slow for some common numbers.
-
-// Magic constant, 0x43300000
-instruct loadConI_x43300000(iRegI dst) %{
- effect(DEF dst);
- size(4);
- format %{ "SETHI HI(0x43300000),$dst\t! 2^52" %}
- ins_encode(SetHi22(0x43300000, dst));
- ins_pipe(ialu_none);
-%}
-
-// Magic constant, 0x41f00000
-instruct loadConI_x41f00000(iRegI dst) %{
- effect(DEF dst);
- size(4);
- format %{ "SETHI HI(0x41f00000),$dst\t! 2^32" %}
- ins_encode(SetHi22(0x41f00000, dst));
- ins_pipe(ialu_none);
-%}
-
-// Construct a double from two float halves
-instruct regDHi_regDLo_to_regD(regD_low dst, regD_low src1, regD_low src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(8);
- format %{ "FMOVS $src1.hi,$dst.hi\n\t"
- "FMOVS $src2.lo,$dst.lo" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmovs_opf);
- ins_encode(form3_opf_rs2D_hi_rdD_hi(src1, dst), form3_opf_rs2D_lo_rdD_lo(src2, dst));
- ins_pipe(faddD_reg_reg);
-%}
-
-// Convert integer in high half of a double register (in the lower half of
-// the double register file) to double
-instruct convI2D_regDHi_regD(regD dst, regD_low src) %{
- effect(DEF dst, USE src);
- size(4);
- format %{ "FITOD $src,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf);
- ins_encode(form3_opf_rs2D_rdD(src, dst));
- ins_pipe(fcvtLHi2D);
-%}
-
-// Add float double precision
-instruct addD_regD_regD(regD dst, regD src1, regD src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "FADDD $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::faddd_opf);
- ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst));
- ins_pipe(faddD_reg_reg);
-%}
-
-// Sub float double precision
-instruct subD_regD_regD(regD dst, regD src1, regD src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "FSUBD $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fsubd_opf);
- ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst));
- ins_pipe(faddD_reg_reg);
-%}
-
-// Mul float double precision
-instruct mulD_regD_regD(regD dst, regD src1, regD src2) %{
- effect(DEF dst, USE src1, USE src2);
- size(4);
- format %{ "FMULD $src1,$src2,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmuld_opf);
- ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst));
- ins_pipe(fmulD_reg_reg);
-%}
-
-// Long to Double conversion using fast fxtof
-instruct convL2D_helper(regD dst, regD tmp) %{
- effect(DEF dst, USE tmp);
- size(4);
- format %{ "FXTOD $tmp,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fxtod_opf);
- ins_encode(form3_opf_rs2D_rdD(tmp, dst));
- ins_pipe(fcvtL2D);
-%}
-
-instruct convL2D_stk_fast_fxtof(regD dst, stackSlotL src) %{
- match(Set dst (ConvL2D src));
- ins_cost(DEFAULT_COST + 3 * MEMORY_REF_COST);
- expand %{
- regD tmp;
- stkL_to_regD(tmp, src);
- convL2D_helper(dst, tmp);
- %}
-%}
-
-instruct convL2D_reg(regD dst, iRegL src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvL2D src));
- expand %{
- regD tmp;
- MoveL2D_reg_reg(tmp, src);
- convL2D_helper(dst, tmp);
- %}
-%}
-
-// Long to Float conversion using fast fxtof
-instruct convL2F_helper(regF dst, regD tmp) %{
- effect(DEF dst, USE tmp);
- size(4);
- format %{ "FXTOS $tmp,$dst" %}
- opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fxtos_opf);
- ins_encode(form3_opf_rs2D_rdF(tmp, dst));
- ins_pipe(fcvtL2F);
-%}
-
-instruct convL2F_stk_fast_fxtof(regF dst, stackSlotL src) %{
- match(Set dst (ConvL2F src));
- ins_cost(DEFAULT_COST + MEMORY_REF_COST);
- expand %{
- regD tmp;
- stkL_to_regD(tmp, src);
- convL2F_helper(dst, tmp);
- %}
-%}
-
-instruct convL2F_reg(regF dst, iRegL src) %{
- predicate(UseVIS >= 3);
- match(Set dst (ConvL2F src));
- ins_cost(DEFAULT_COST);
- expand %{
- regD tmp;
- MoveL2D_reg_reg(tmp, src);
- convL2F_helper(dst, tmp);
- %}
-%}
-
-//-----------
-
-instruct convL2I_reg(iRegI dst, iRegL src) %{
- match(Set dst (ConvL2I src));
- size(4);
- format %{ "SRA $src,R_G0,$dst\t! long->int" %}
- ins_encode( form3_rs1_rd_signextend_lo1( src, dst ) );
- ins_pipe(ialu_reg);
-%}
-
-// Register Shift Right Immediate
-instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt) %{
- match(Set dst (ConvL2I (RShiftL src cnt)));
-
- size(4);
- format %{ "SRAX $src,$cnt,$dst" %}
- opcode(Assembler::srax_op3, Assembler::arith_op);
- ins_encode( form3_sd_rs1_imm6_rd( src, cnt, dst ) );
- ins_pipe(ialu_reg_imm);
-%}
-
-//----------Control Flow Instructions------------------------------------------
-// Compare Instructions
-// Compare Integers
-instruct compI_iReg(flagsReg icc, iRegI op1, iRegI op2) %{
- match(Set icc (CmpI op1 op2));
- effect( DEF icc, USE op1, USE op2 );
-
- size(4);
- format %{ "CMP $op1,$op2" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{
- match(Set icc (CmpU op1 op2));
-
- size(4);
- format %{ "CMP $op1,$op2\t! unsigned" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct compUL_iReg(flagsRegUL xcc, iRegL op1, iRegL op2) %{
- match(Set xcc (CmpUL op1 op2));
- effect(DEF xcc, USE op1, USE op2);
-
- size(4);
- format %{ "CMP $op1,$op2\t! unsigned long" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode(form3_rs1_rs2_rd(op1, op2, R_G0));
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct compI_iReg_imm13(flagsReg icc, iRegI op1, immI13 op2) %{
- match(Set icc (CmpI op1 op2));
- effect( DEF icc, USE op1 );
-
- size(4);
- format %{ "CMP $op1,$op2" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_imm);
-%}
-
-instruct testI_reg_reg( flagsReg icc, iRegI op1, iRegI op2, immI0 zero ) %{
- match(Set icc (CmpI (AndI op1 op2) zero));
-
- size(4);
- format %{ "BTST $op2,$op1" %}
- opcode(Assembler::andcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg_zero);
-%}
-
-instruct testI_reg_imm( flagsReg icc, iRegI op1, immI13 op2, immI0 zero ) %{
- match(Set icc (CmpI (AndI op1 op2) zero));
-
- size(4);
- format %{ "BTST $op2,$op1" %}
- opcode(Assembler::andcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_imm_zero);
-%}
-
-instruct compL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2 ) %{
- match(Set xcc (CmpL op1 op2));
- effect( DEF xcc, USE op1, USE op2 );
-
- size(4);
- format %{ "CMP $op1,$op2\t\t! long" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct compL_reg_con(flagsRegL xcc, iRegL op1, immL13 con) %{
- match(Set xcc (CmpL op1 con));
- effect( DEF xcc, USE op1, USE con );
-
- size(4);
- format %{ "CMP $op1,$con\t\t! long" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, con, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct testL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2, immL0 zero) %{
- match(Set xcc (CmpL (AndL op1 op2) zero));
- effect( DEF xcc, USE op1, USE op2 );
-
- size(4);
- format %{ "BTST $op1,$op2\t\t! long" %}
- opcode(Assembler::andcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-// useful for checking the alignment of a pointer:
-instruct testL_reg_con(flagsRegL xcc, iRegL op1, immL13 con, immL0 zero) %{
- match(Set xcc (CmpL (AndL op1 con) zero));
- effect( DEF xcc, USE op1, USE con );
-
- size(4);
- format %{ "BTST $op1,$con\t\t! long" %}
- opcode(Assembler::andcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, con, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct compU_iReg_imm13(flagsRegU icc, iRegI op1, immU12 op2 ) %{
- match(Set icc (CmpU op1 op2));
-
- size(4);
- format %{ "CMP $op1,$op2\t! unsigned" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_imm);
-%}
-
-instruct compUL_iReg_imm13(flagsRegUL xcc, iRegL op1, immUL12 op2) %{
- match(Set xcc (CmpUL op1 op2));
- effect(DEF xcc, USE op1, USE op2);
-
- size(4);
- format %{ "CMP $op1,$op2\t! unsigned long" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode(form3_rs1_simm13_rd(op1, op2, R_G0));
- ins_pipe(ialu_cconly_reg_imm);
-%}
-
-// Compare Pointers
-instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{
- match(Set pcc (CmpP op1 op2));
-
- size(4);
- format %{ "CMP $op1,$op2\t! ptr" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct compP_iRegP_imm13(flagsRegP pcc, iRegP op1, immP13 op2 ) %{
- match(Set pcc (CmpP op1 op2));
-
- size(4);
- format %{ "CMP $op1,$op2\t! ptr" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_imm);
-%}
-
-// Compare Narrow oops
-instruct compN_iRegN(flagsReg icc, iRegN op1, iRegN op2 ) %{
- match(Set icc (CmpN op1 op2));
-
- size(4);
- format %{ "CMP $op1,$op2\t! compressed ptr" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_reg);
-%}
-
-instruct compN_iRegN_immN0(flagsReg icc, iRegN op1, immN0 op2 ) %{
- match(Set icc (CmpN op1 op2));
-
- size(4);
- format %{ "CMP $op1,$op2\t! compressed ptr" %}
- opcode(Assembler::subcc_op3, Assembler::arith_op);
- ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) );
- ins_pipe(ialu_cconly_reg_imm);
-%}
-
-//----------Max and Min--------------------------------------------------------
-// Min Instructions
-// Conditional move for min
-instruct cmovI_reg_lt( iRegI op2, iRegI op1, flagsReg icc ) %{
- effect( USE_DEF op2, USE op1, USE icc );
-
- size(4);
- format %{ "MOVlt icc,$op1,$op2\t! min" %}
- opcode(Assembler::less);
- ins_encode( enc_cmov_reg_minmax(op2,op1) );
- ins_pipe(ialu_reg_flags);
-%}
-
-// Min Register with Register.
-instruct minI_eReg(iRegI op1, iRegI op2) %{
- match(Set op2 (MinI op1 op2));
- ins_cost(DEFAULT_COST*2);
- expand %{
- flagsReg icc;
- compI_iReg(icc,op1,op2);
- cmovI_reg_lt(op2,op1,icc);
- %}
-%}
-
-// Max Instructions
-// Conditional move for max
-instruct cmovI_reg_gt( iRegI op2, iRegI op1, flagsReg icc ) %{
- effect( USE_DEF op2, USE op1, USE icc );
- format %{ "MOVgt icc,$op1,$op2\t! max" %}
- opcode(Assembler::greater);
- ins_encode( enc_cmov_reg_minmax(op2,op1) );
- ins_pipe(ialu_reg_flags);
-%}
-
-// Max Register with Register
-instruct maxI_eReg(iRegI op1, iRegI op2) %{
- match(Set op2 (MaxI op1 op2));
- ins_cost(DEFAULT_COST*2);
- expand %{
- flagsReg icc;
- compI_iReg(icc,op1,op2);
- cmovI_reg_gt(op2,op1,icc);
- %}
-%}
-
-
-//----------Float Compares----------------------------------------------------
-// Compare floating, generate condition code
-instruct cmpF_cc(flagsRegF fcc, regF src1, regF src2) %{
- match(Set fcc (CmpF src1 src2));
-
- size(4);
- format %{ "FCMPs $fcc,$src1,$src2" %}
- opcode(Assembler::fpop2_op3, Assembler::arith_op, Assembler::fcmps_opf);
- ins_encode( form3_opf_rs1F_rs2F_fcc( src1, src2, fcc ) );
- ins_pipe(faddF_fcc_reg_reg_zero);
-%}
-
-instruct cmpD_cc(flagsRegF fcc, regD src1, regD src2) %{
- match(Set fcc (CmpD src1 src2));
-
- size(4);
- format %{ "FCMPd $fcc,$src1,$src2" %}
- opcode(Assembler::fpop2_op3, Assembler::arith_op, Assembler::fcmpd_opf);
- ins_encode( form3_opf_rs1D_rs2D_fcc( src1, src2, fcc ) );
- ins_pipe(faddD_fcc_reg_reg_zero);
-%}
-
-
-// Compare floating, generate -1,0,1
-instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsRegF0 fcc0) %{
- match(Set dst (CmpF3 src1 src2));
- effect(KILL fcc0);
- ins_cost(DEFAULT_COST*3+BRANCH_COST*3);
- format %{ "fcmpl $dst,$src1,$src2" %}
- // Primary = float
- opcode( true );
- ins_encode( floating_cmp( dst, src1, src2 ) );
- ins_pipe( floating_cmp );
-%}
-
-instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsRegF0 fcc0) %{
- match(Set dst (CmpD3 src1 src2));
- effect(KILL fcc0);
- ins_cost(DEFAULT_COST*3+BRANCH_COST*3);
- format %{ "dcmpl $dst,$src1,$src2" %}
- // Primary = double (not float)
- opcode( false );
- ins_encode( floating_cmp( dst, src1, src2 ) );
- ins_pipe( floating_cmp );
-%}
-
-//----------Branches---------------------------------------------------------
-// Jump
-// (compare 'operand indIndex' and 'instruct addP_reg_reg' above)
-instruct jumpXtnd(iRegX switch_val, o7RegI table) %{
- match(Jump switch_val);
- effect(TEMP table);
-
- ins_cost(350);
-
- format %{ "ADD $constanttablebase, $constantoffset, O7\n\t"
- "LD [O7 + $switch_val], O7\n\t"
- "JUMP O7" %}
- ins_encode %{
- // Calculate table address into a register.
- Register table_reg;
- Register label_reg = O7;
- // If we are calculating the size of this instruction don't trust
- // zero offsets because they might change when
- // MachConstantBaseNode decides to optimize the constant table
- // base.
- if ((constant_offset() == 0) && !Compile::current()->output()->in_scratch_emit_size()) {
- table_reg = $constanttablebase;
- } else {
- table_reg = O7;
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset, O7);
- __ add($constanttablebase, con_offset, table_reg);
- }
-
- // Jump to base address + switch value
- __ ld_ptr(table_reg, $switch_val$$Register, label_reg);
- __ jmp(label_reg, G0);
- __ delayed()->nop();
- %}
- ins_pipe(ialu_reg_reg);
-%}
-
-// Direct Branch. Use V8 version with longer range.
-instruct branch(label labl) %{
- match(Goto);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BA $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- __ ba(*L);
- __ delayed()->nop();
- %}
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br);
-%}
-
-// Direct Branch, short with no delay slot
-instruct branch_short(label labl) %{
- match(Goto);
- predicate(UseCBCond);
- effect(USE labl);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "BA $labl\t! short branch" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ ba_short(*L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_imm);
-%}
-
-// Conditional Direct Branch
-instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{
- match(If cmp icc);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BP$cmp $icc,$labl" %}
- // Prim = bits 24-22, Secnd = bits 31-30
- ins_encode( enc_bp( labl, cmp, icc ) );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_cc);
-%}
-
-instruct branchConU(cmpOpU cmp, flagsRegU icc, label labl) %{
- match(If cmp icc);
- effect(USE labl);
-
- ins_cost(BRANCH_COST);
- format %{ "BP$cmp $icc,$labl" %}
- // Prim = bits 24-22, Secnd = bits 31-30
- ins_encode( enc_bp( labl, cmp, icc ) );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_cc);
-%}
-
-instruct branchConP(cmpOpP cmp, flagsRegP pcc, label labl) %{
- match(If cmp pcc);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BP$cmp $pcc,$labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
-
- __ bp( (Assembler::Condition)($cmp$$cmpcode), false, Assembler::ptr_cc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_cc);
-%}
-
-instruct branchConF(cmpOpF cmp, flagsRegF fcc, label labl) %{
- match(If cmp fcc);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "FBP$cmp $fcc,$labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
-
- __ fbp( (Assembler::Condition)($cmp$$cmpcode), false, (Assembler::CC)($fcc$$reg), predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_fcc);
-%}
-
-instruct branchLoopEnd(cmpOp cmp, flagsReg icc, label labl) %{
- match(CountedLoopEnd cmp icc);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BP$cmp $icc,$labl\t! Loop end" %}
- // Prim = bits 24-22, Secnd = bits 31-30
- ins_encode( enc_bp( labl, cmp, icc ) );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_cc);
-%}
-
-instruct branchLoopEndU(cmpOpU cmp, flagsRegU icc, label labl) %{
- match(CountedLoopEnd cmp icc);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BP$cmp $icc,$labl\t! Loop end" %}
- // Prim = bits 24-22, Secnd = bits 31-30
- ins_encode( enc_bp( labl, cmp, icc ) );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_cc);
-%}
-
-// Compare and branch instructions
-instruct cmpI_reg_branch(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
- match(If cmp (CmpI op1 op2));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! int\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$Register);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpI_imm_branch(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
- match(If cmp (CmpI op1 op2));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! int\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$constant);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_imm);
-%}
-
-instruct cmpU_reg_branch(cmpOpU cmp, iRegI op1, iRegI op2, label labl, flagsRegU icc) %{
- match(If cmp (CmpU op1 op2));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! unsigned\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$Register);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpU_imm_branch(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU icc) %{
- match(If cmp (CmpU op1 op2));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! unsigned\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$constant);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_imm);
-%}
-
-instruct cmpUL_reg_branch(cmpOpU cmp, iRegL op1, iRegL op2, label labl, flagsRegUL xcc) %{
- match(If cmp (CmpUL op1 op2));
- effect(USE labl, KILL xcc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! unsigned long\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$Register);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpUL_imm_branch(cmpOpU cmp, iRegL op1, immL5 op2, label labl, flagsRegUL xcc) %{
- match(If cmp (CmpUL op1 op2));
- effect(USE labl, KILL xcc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! unsigned long\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$constant);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_imm);
-%}
-
-instruct cmpL_reg_branch(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{
- match(If cmp (CmpL op1 op2));
- effect(USE labl, KILL xcc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! long\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$Register);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpL_imm_branch(cmpOp cmp, iRegL op1, immL5 op2, label labl, flagsRegL xcc) %{
- match(If cmp (CmpL op1 op2));
- effect(USE labl, KILL xcc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! long\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$constant);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_imm);
-%}
-
-// Compare Pointers and branch
-instruct cmpP_reg_branch(cmpOpP cmp, iRegP op1, iRegP op2, label labl, flagsRegP pcc) %{
- match(If cmp (CmpP op1 op2));
- effect(USE labl, KILL pcc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! ptr\n\t"
- "B$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$Register);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::ptr_cc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpP_null_branch(cmpOpP cmp, iRegP op1, immP0 null, label labl, flagsRegP pcc) %{
- match(If cmp (CmpP op1 null));
- effect(USE labl, KILL pcc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,0\t! ptr\n\t"
- "B$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, G0);
- // bpr() is not used here since it has shorter distance.
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::ptr_cc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpN_reg_branch(cmpOp cmp, iRegN op1, iRegN op2, label labl, flagsReg icc) %{
- match(If cmp (CmpN op1 op2));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! compressed ptr\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$Register);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpN_null_branch(cmpOp cmp, iRegN op1, immN0 null, label labl, flagsReg icc) %{
- match(If cmp (CmpN op1 null));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,0\t! compressed ptr\n\t"
- "BP$cmp $labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, G0);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-// Loop back branch
-instruct cmpI_reg_branchLoopEnd(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
- match(CountedLoopEnd cmp (CmpI op1 op2));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! int\n\t"
- "BP$cmp $labl\t! Loop end" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$Register);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_reg);
-%}
-
-instruct cmpI_imm_branchLoopEnd(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
- match(CountedLoopEnd cmp (CmpI op1 op2));
- effect(USE labl, KILL icc);
-
- size(12);
- ins_cost(BRANCH_COST);
- format %{ "CMP $op1,$op2\t! int\n\t"
- "BP$cmp $labl\t! Loop end" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
- __ cmp($op1$$Register, $op2$$constant);
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_pipe(cmp_br_reg_imm);
-%}
-
-// Short compare and branch instructions
-instruct cmpI_reg_branch_short(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
- match(If cmp (CmpI op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,$op2,$labl\t! int" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpI_imm_branch_short(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
- match(If cmp (CmpI op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,$op2,$labl\t! int" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_imm);
-%}
-
-instruct cmpU_reg_branch_short(cmpOpU cmp, iRegI op1, iRegI op2, label labl, flagsRegU icc) %{
- match(If cmp (CmpU op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,$op2,$labl\t! unsigned" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpU_imm_branch_short(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU icc) %{
- match(If cmp (CmpU op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,$op2,$labl\t! unsigned" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_imm);
-%}
-
-instruct cmpUL_reg_branch_short(cmpOpU cmp, iRegL op1, iRegL op2, label labl, flagsRegUL xcc) %{
- match(If cmp (CmpUL op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL xcc);
-
- size(4);
- ins_cost(BRANCH_COST);
- format %{ "CXB$cmp $op1,$op2,$labl\t! unsigned long" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$Register, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpUL_imm_branch_short(cmpOpU cmp, iRegL op1, immL5 op2, label labl, flagsRegUL xcc) %{
- match(If cmp (CmpUL op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL xcc);
-
- size(4);
- ins_cost(BRANCH_COST);
- format %{ "CXB$cmp $op1,$op2,$labl\t! unsigned long" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$constant, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_imm);
-%}
-
-instruct cmpL_reg_branch_short(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{
- match(If cmp (CmpL op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL xcc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CXB$cmp $op1,$op2,$labl\t! long" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$Register, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpL_imm_branch_short(cmpOp cmp, iRegL op1, immL5 op2, label labl, flagsRegL xcc) %{
- match(If cmp (CmpL op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL xcc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CXB$cmp $op1,$op2,$labl\t! long" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$constant, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_imm);
-%}
-
-// Compare Pointers and branch
-instruct cmpP_reg_branch_short(cmpOpP cmp, iRegP op1, iRegP op2, label labl, flagsRegP pcc) %{
- match(If cmp (CmpP op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL pcc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CXB$cmp $op1,$op2,$labl\t! ptr" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::ptr_cc, $op1$$Register, $op2$$Register, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpP_null_branch_short(cmpOpP cmp, iRegP op1, immP0 null, label labl, flagsRegP pcc) %{
- match(If cmp (CmpP op1 null));
- predicate(UseCBCond);
- effect(USE labl, KILL pcc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CXB$cmp $op1,0,$labl\t! ptr" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::ptr_cc, $op1$$Register, G0, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpN_reg_branch_short(cmpOp cmp, iRegN op1, iRegN op2, label labl, flagsReg icc) %{
- match(If cmp (CmpN op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,$op2,$labl\t! compressed ptr" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpN_null_branch_short(cmpOp cmp, iRegN op1, immN0 null, label labl, flagsReg icc) %{
- match(If cmp (CmpN op1 null));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,0,$labl\t! compressed ptr" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, G0, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-// Loop back branch
-instruct cmpI_reg_branchLoopEnd_short(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{
- match(CountedLoopEnd cmp (CmpI op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,$op2,$labl\t! Loop end" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_reg);
-%}
-
-instruct cmpI_imm_branchLoopEnd_short(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{
- match(CountedLoopEnd cmp (CmpI op1 op2));
- predicate(UseCBCond);
- effect(USE labl, KILL icc);
-
- size(4); // Assuming no NOP inserted.
- ins_cost(BRANCH_COST);
- format %{ "CWB$cmp $op1,$op2,$labl\t! Loop end" %}
- ins_encode %{
- Label* L = $labl$$label;
- assert(__ use_cbcond(*L), "back to back cbcond");
- __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L);
- %}
- ins_short_branch(1);
- ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER);
- ins_pipe(cbcond_reg_imm);
-%}
-
-// Branch-on-register tests all 64 bits. We assume that values
-// in 64-bit registers always remains zero or sign extended
-// unless our code munges the high bits. Interrupts can chop
-// the high order bits to zero or sign at any time.
-instruct branchCon_regI(cmpOp_reg cmp, iRegI op1, immI0 zero, label labl) %{
- match(If cmp (CmpI op1 zero));
- predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BR$cmp $op1,$labl" %}
- ins_encode( enc_bpr( labl, cmp, op1 ) );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_reg);
-%}
-
-instruct branchCon_regP(cmpOp_reg cmp, iRegP op1, immP0 null, label labl) %{
- match(If cmp (CmpP op1 null));
- predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BR$cmp $op1,$labl" %}
- ins_encode( enc_bpr( labl, cmp, op1 ) );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_reg);
-%}
-
-instruct branchCon_regL(cmpOp_reg cmp, iRegL op1, immL0 zero, label labl) %{
- match(If cmp (CmpL op1 zero));
- predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf));
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BR$cmp $op1,$labl" %}
- ins_encode( enc_bpr( labl, cmp, op1 ) );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_reg);
-%}
-
-
-// ============================================================================
-// Long Compare
-//
-// Currently we hold longs in 2 registers. Comparing such values efficiently
-// is tricky. The flavor of compare used depends on whether we are testing
-// for LT, LE, or EQ. For a simple LT test we can check just the sign bit.
-// The GE test is the negated LT test. The LE test can be had by commuting
-// the operands (yielding a GE test) and then negating; negate again for the
-// GT test. The EQ test is done by ORcc'ing the high and low halves, and the
-// NE test is negated from that.
-
-// Due to a shortcoming in the ADLC, it mixes up expressions like:
-// (foo (CmpI (CmpL X Y) 0)) and (bar (CmpI (CmpL X 0L) 0)). Note the
-// difference between 'Y' and '0L'. The tree-matches for the CmpI sections
-// are collapsed internally in the ADLC's dfa-gen code. The match for
-// (CmpI (CmpL X Y) 0) is silently replaced with (CmpI (CmpL X 0L) 0) and the
-// foo match ends up with the wrong leaf. One fix is to not match both
-// reg-reg and reg-zero forms of long-compare. This is unfortunate because
-// both forms beat the trinary form of long-compare and both are very useful
-// on Intel which has so few registers.
-
-instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{
- match(If cmp xcc);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BP$cmp $xcc,$labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
-
- __ bp( (Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_cc);
-%}
-
-instruct branchConU_long(cmpOpU cmp, flagsRegUL xcc, label labl) %{
- match(If cmp xcc);
- effect(USE labl);
-
- size(8);
- ins_cost(BRANCH_COST);
- format %{ "BP$cmp $xcc,$labl" %}
- ins_encode %{
- Label* L = $labl$$label;
- Assembler::Predict predict_taken =
- cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn;
-
- __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L);
- __ delayed()->nop();
- %}
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(br_cc);
-%}
-
-// Manifest a CmpL3 result in an integer register. Very painful.
-// This is the test to avoid.
-instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{
- match(Set dst (CmpL3 src1 src2) );
- effect( KILL ccr );
- ins_cost(6*DEFAULT_COST);
- size(24);
- format %{ "CMP $src1,$src2\t\t! long\n"
- "\tBLT,a,pn done\n"
- "\tMOV -1,$dst\t! delay slot\n"
- "\tBGT,a,pn done\n"
- "\tMOV 1,$dst\t! delay slot\n"
- "\tCLR $dst\n"
- "done:" %}
- ins_encode( cmpl_flag(src1,src2,dst) );
- ins_pipe(cmpL_reg);
-%}
-
-// Conditional move
-instruct cmovLL_reg(cmpOp cmp, flagsRegL xcc, iRegL dst, iRegL src) %{
- match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $xcc,$src,$dst\t! long" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovLL_imm(cmpOp cmp, flagsRegL xcc, iRegL dst, immL0 src) %{
- match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
- ins_cost(140);
- format %{ "MOV$cmp $xcc,$src,$dst\t! long" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovIL_reg(cmpOp cmp, flagsRegL xcc, iRegI dst, iRegI src) %{
- match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $xcc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovIL_imm(cmpOp cmp, flagsRegL xcc, iRegI dst, immI11 src) %{
- match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
- ins_cost(140);
- format %{ "MOV$cmp $xcc,$src,$dst" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovNL_reg(cmpOp cmp, flagsRegL xcc, iRegN dst, iRegN src) %{
- match(Set dst (CMoveN (Binary cmp xcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $xcc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovPL_reg(cmpOp cmp, flagsRegL xcc, iRegP dst, iRegP src) %{
- match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
- ins_cost(150);
- format %{ "MOV$cmp $xcc,$src,$dst" %}
- ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(ialu_reg);
-%}
-
-instruct cmovPL_imm(cmpOp cmp, flagsRegL xcc, iRegP dst, immP0 src) %{
- match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
- ins_cost(140);
- format %{ "MOV$cmp $xcc,$src,$dst" %}
- ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(ialu_imm);
-%}
-
-instruct cmovFL_reg(cmpOp cmp, flagsRegL xcc, regF dst, regF src) %{
- match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
- ins_cost(150);
- opcode(0x101);
- format %{ "FMOVS$cmp $xcc,$src,$dst" %}
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(int_conditional_float_move);
-%}
-
-instruct cmovDL_reg(cmpOp cmp, flagsRegL xcc, regD dst, regD src) %{
- match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
- ins_cost(150);
- opcode(0x102);
- format %{ "FMOVD$cmp $xcc,$src,$dst" %}
- ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::xcc)) );
- ins_pipe(int_conditional_float_move);
-%}
-
-// ============================================================================
-// Safepoint Instruction
-instruct safePoint_poll(iRegP poll) %{
- match(SafePoint poll);
- effect(USE poll);
-
- size(4);
- format %{ "LDX [$poll],R_G0\t! Safepoint: poll for GC" %}
- ins_encode %{
- __ relocate(relocInfo::poll_type);
- __ ld_ptr($poll$$Register, 0, G0);
- %}
- ins_pipe(loadPollP);
-%}
-
-// ============================================================================
-// Call Instructions
-// Call Java Static Instruction
-instruct CallStaticJavaDirect( method meth ) %{
- match(CallStaticJava);
- predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke());
- effect(USE meth);
-
- size(8);
- ins_cost(CALL_COST);
- format %{ "CALL,static ; NOP ==> " %}
- ins_encode( Java_Static_Call( meth ), call_epilog );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(simple_call);
-%}
-
-// Call Java Static Instruction (method handle version)
-instruct CallStaticJavaHandle(method meth, l7RegP l7_mh_SP_save) %{
- match(CallStaticJava);
- predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke());
- effect(USE meth, KILL l7_mh_SP_save);
-
- size(16);
- ins_cost(CALL_COST);
- format %{ "CALL,static/MethodHandle" %}
- ins_encode(preserve_SP, Java_Static_Call(meth), restore_SP, call_epilog);
- ins_pipe(simple_call);
-%}
-
-// Call Java Dynamic Instruction
-instruct CallDynamicJavaDirect( method meth ) %{
- match(CallDynamicJava);
- effect(USE meth);
-
- ins_cost(CALL_COST);
- format %{ "SET (empty),R_G5\n\t"
- "CALL,dynamic ; NOP ==> " %}
- ins_encode( Java_Dynamic_Call( meth ), call_epilog );
- ins_pipe(call);
-%}
-
-// Call Runtime Instruction
-instruct CallRuntimeDirect(method meth, l7RegP l7) %{
- match(CallRuntime);
- effect(USE meth, KILL l7);
- ins_cost(CALL_COST);
- format %{ "CALL,runtime" %}
- ins_encode( Java_To_Runtime( meth ),
- call_epilog, adjust_long_from_native_call );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(simple_call);
-%}
-
-// Call runtime without safepoint - same as CallRuntime
-instruct CallLeafDirect(method meth, l7RegP l7) %{
- match(CallLeaf);
- effect(USE meth, KILL l7);
- ins_cost(CALL_COST);
- format %{ "CALL,runtime leaf" %}
- ins_encode( Java_To_Runtime( meth ),
- call_epilog,
- adjust_long_from_native_call );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(simple_call);
-%}
-
-// Call runtime without safepoint - same as CallLeaf
-instruct CallLeafNoFPDirect(method meth, l7RegP l7) %{
- match(CallLeafNoFP);
- effect(USE meth, KILL l7);
- ins_cost(CALL_COST);
- format %{ "CALL,runtime leaf nofp" %}
- ins_encode( Java_To_Runtime( meth ),
- call_epilog,
- adjust_long_from_native_call );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(simple_call);
-%}
-
-// Tail Call; Jump from runtime stub to Java code.
-// Also known as an 'interprocedural jump'.
-// Target of jump will eventually return to caller.
-// TailJump below removes the return address.
-instruct TailCalljmpInd(g3RegP jump_target, inline_cache_regP method_oop) %{
- match(TailCall jump_target method_oop );
-
- ins_cost(CALL_COST);
- format %{ "Jmp $jump_target ; NOP \t! $method_oop holds method oop" %}
- ins_encode(form_jmpl(jump_target));
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(tail_call);
-%}
-
-
-// Return Instruction
-instruct Ret() %{
- match(Return);
-
- // The epilogue node did the ret already.
- size(0);
- format %{ "! return" %}
- ins_encode();
- ins_pipe(empty);
-%}
-
-
-// Tail Jump; remove the return address; jump to target.
-// TailCall above leaves the return address around.
-// TailJump is used in only one place, the rethrow_Java stub (fancy_jump=2).
-// ex_oop (Exception Oop) is needed in %o0 at the jump. As there would be a
-// "restore" before this instruction (in Epilogue), we need to materialize it
-// in %i0.
-instruct tailjmpInd(g1RegP jump_target, i0RegP ex_oop) %{
- match( TailJump jump_target ex_oop );
- ins_cost(CALL_COST);
- format %{ "! discard R_O7\n\t"
- "Jmp $jump_target ; ADD O7,8,O1 \t! $ex_oop holds exc. oop" %}
- ins_encode(form_jmpl_set_exception_pc(jump_target));
- // opcode(Assembler::jmpl_op3, Assembler::arith_op);
- // The hack duplicates the exception oop into G3, so that CreateEx can use it there.
- // ins_encode( form3_rs1_simm13_rd( jump_target, 0x00, R_G0 ), move_return_pc_to_o1() );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(tail_call);
-%}
-
-// Create exception oop: created by stack-crawling runtime code.
-// Created exception is now available to this handler, and is setup
-// just prior to jumping to this handler. No code emitted.
-instruct CreateException( o0RegP ex_oop )
-%{
- match(Set ex_oop (CreateEx));
- ins_cost(0);
-
- size(0);
- // use the following format syntax
- format %{ "! exception oop is in R_O0; no code emitted" %}
- ins_encode();
- ins_pipe(empty);
-%}
-
-
-// Rethrow exception:
-// The exception oop will come in the first argument position.
-// Then JUMP (not call) to the rethrow stub code.
-instruct RethrowException()
-%{
- match(Rethrow);
- ins_cost(CALL_COST);
-
- // use the following format syntax
- format %{ "Jmp rethrow_stub" %}
- ins_encode(enc_rethrow);
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(tail_call);
-%}
-
-
-// Die now
-instruct ShouldNotReachHere( )
-%{
- match(Halt);
- ins_cost(CALL_COST);
-
- size(4);
- // Use the following format syntax
- format %{ "ILLTRAP ; ShouldNotReachHere" %}
- ins_encode( form2_illtrap() );
- ins_pipe(tail_call);
-%}
-
-// ============================================================================
-// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass
-// array for an instance of the superklass. Set a hidden internal cache on a
-// hit (cache is checked with exposed code in gen_subtype_check()). Return
-// not zero for a miss or zero for a hit. The encoding ALSO sets flags.
-instruct partialSubtypeCheck( o0RegP index, o1RegP sub, o2RegP super, flagsRegP pcc, o7RegP o7 ) %{
- match(Set index (PartialSubtypeCheck sub super));
- effect( KILL pcc, KILL o7 );
- ins_cost(DEFAULT_COST*10);
- format %{ "CALL PartialSubtypeCheck\n\tNOP" %}
- ins_encode( enc_PartialSubtypeCheck() );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(partial_subtype_check_pipe);
-%}
-
-instruct partialSubtypeCheck_vs_zero( flagsRegP pcc, o1RegP sub, o2RegP super, immP0 zero, o0RegP idx, o7RegP o7 ) %{
- match(Set pcc (CmpP (PartialSubtypeCheck sub super) zero));
- effect( KILL idx, KILL o7 );
- ins_cost(DEFAULT_COST*10);
- format %{ "CALL PartialSubtypeCheck\n\tNOP\t# (sets condition codes)" %}
- ins_encode( enc_PartialSubtypeCheck() );
- ins_avoid_back_to_back(AVOID_BEFORE);
- ins_pipe(partial_subtype_check_pipe);
-%}
-
-
-// ============================================================================
-// inlined locking and unlocking
-
-instruct cmpFastLock(flagsRegP pcc, iRegP object, o1RegP box, iRegP scratch2, o7RegP scratch ) %{
- match(Set pcc (FastLock object box));
-
- effect(TEMP scratch2, USE_KILL box, KILL scratch);
- ins_cost(100);
-
- format %{ "FASTLOCK $object,$box\t! kills $box,$scratch,$scratch2" %}
- ins_encode( Fast_Lock(object, box, scratch, scratch2) );
- ins_pipe(long_memory_op);
-%}
-
-
-instruct cmpFastUnlock(flagsRegP pcc, iRegP object, o1RegP box, iRegP scratch2, o7RegP scratch ) %{
- match(Set pcc (FastUnlock object box));
- effect(TEMP scratch2, USE_KILL box, KILL scratch);
- ins_cost(100);
-
- format %{ "FASTUNLOCK $object,$box\t! kills $box,$scratch,$scratch2" %}
- ins_encode( Fast_Unlock(object, box, scratch, scratch2) );
- ins_pipe(long_memory_op);
-%}
-
-// The encodings are generic.
-instruct clear_array(iRegX cnt, iRegP base, iRegX temp, Universe dummy, flagsReg ccr) %{
- predicate(!use_block_zeroing(n->in(2)) );
- match(Set dummy (ClearArray cnt base));
- effect(TEMP temp, KILL ccr);
- ins_cost(300);
- format %{ "MOV $cnt,$temp\n"
- "loop: SUBcc $temp,8,$temp\t! Count down a dword of bytes\n"
- " BRge loop\t\t! Clearing loop\n"
- " STX G0,[$base+$temp]\t! delay slot" %}
-
- ins_encode %{
- // Compiler ensures base is doubleword aligned and cnt is count of doublewords
- Register nof_bytes_arg = $cnt$$Register;
- Register nof_bytes_tmp = $temp$$Register;
- Register base_pointer_arg = $base$$Register;
-
- Label loop;
- __ mov(nof_bytes_arg, nof_bytes_tmp);
-
- // Loop and clear, walking backwards through the array.
- // nof_bytes_tmp (if >0) is always the number of bytes to zero
- __ bind(loop);
- __ deccc(nof_bytes_tmp, 8);
- __ br(Assembler::greaterEqual, true, Assembler::pt, loop);
- __ delayed()-> stx(G0, base_pointer_arg, nof_bytes_tmp);
- // %%%% this mini-loop must not cross a cache boundary!
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct clear_array_bis(g1RegX cnt, o0RegP base, Universe dummy, flagsReg ccr) %{
- predicate(use_block_zeroing(n->in(2)));
- match(Set dummy (ClearArray cnt base));
- effect(USE_KILL cnt, USE_KILL base, KILL ccr);
- ins_cost(300);
- format %{ "CLEAR [$base, $cnt]\t! ClearArray" %}
-
- ins_encode %{
-
- assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation");
- Register to = $base$$Register;
- Register count = $cnt$$Register;
-
- Label Ldone;
- __ nop(); // Separate short branches
- // Use BIS for zeroing (temp is not used).
- __ bis_zeroing(to, count, G0, Ldone);
- __ bind(Ldone);
-
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct clear_array_bis_2(g1RegX cnt, o0RegP base, iRegX tmp, Universe dummy, flagsReg ccr) %{
- predicate(use_block_zeroing(n->in(2)) && !Assembler::is_simm13((int)BlockZeroingLowLimit));
- match(Set dummy (ClearArray cnt base));
- effect(TEMP tmp, USE_KILL cnt, USE_KILL base, KILL ccr);
- ins_cost(300);
- format %{ "CLEAR [$base, $cnt]\t! ClearArray" %}
-
- ins_encode %{
-
- assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation");
- Register to = $base$$Register;
- Register count = $cnt$$Register;
- Register temp = $tmp$$Register;
-
- Label Ldone;
- __ nop(); // Separate short branches
- // Use BIS for zeroing
- __ bis_zeroing(to, count, temp, Ldone);
- __ bind(Ldone);
-
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct string_compareL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result,
- o7RegI tmp, flagsReg ccr) %{
- predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
- match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
- effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp);
- ins_cost(300);
- format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %}
- ins_encode %{
- __ string_compare($str1$$Register, $str2$$Register,
- $cnt1$$Register, $cnt2$$Register,
- $tmp$$Register, $tmp$$Register,
- $result$$Register, StrIntrinsicNode::LL);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct string_compareU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result,
- o7RegI tmp, flagsReg ccr) %{
- predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU);
- match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
- effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp);
- ins_cost(300);
- format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %}
- ins_encode %{
- __ string_compare($str1$$Register, $str2$$Register,
- $cnt1$$Register, $cnt2$$Register,
- $tmp$$Register, $tmp$$Register,
- $result$$Register, StrIntrinsicNode::UU);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct string_compareLU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result,
- o7RegI tmp1, g1RegI tmp2, flagsReg ccr) %{
- predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
- match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
- effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp1, KILL tmp2);
- ins_cost(300);
- format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1,$tmp2" %}
- ins_encode %{
- __ string_compare($str1$$Register, $str2$$Register,
- $cnt1$$Register, $cnt2$$Register,
- $tmp1$$Register, $tmp2$$Register,
- $result$$Register, StrIntrinsicNode::LU);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct string_compareUL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result,
- o7RegI tmp1, g1RegI tmp2, flagsReg ccr) %{
- predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
- match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
- effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp1, KILL tmp2);
- ins_cost(300);
- format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1,$tmp2" %}
- ins_encode %{
- __ string_compare($str2$$Register, $str1$$Register,
- $cnt2$$Register, $cnt1$$Register,
- $tmp1$$Register, $tmp2$$Register,
- $result$$Register, StrIntrinsicNode::UL);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct string_equalsL(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result,
- o7RegI tmp, flagsReg ccr) %{
- predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL);
- match(Set result (StrEquals (Binary str1 str2) cnt));
- effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp, KILL ccr);
- ins_cost(300);
- format %{ "String Equals byte[] $str1,$str2,$cnt -> $result // KILL $tmp" %}
- ins_encode %{
- __ array_equals(false, $str1$$Register, $str2$$Register,
- $cnt$$Register, $tmp$$Register,
- $result$$Register, true /* byte */);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct string_equalsU(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result,
- o7RegI tmp, flagsReg ccr) %{
- 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 tmp, KILL ccr);
- ins_cost(300);
- format %{ "String Equals char[] $str1,$str2,$cnt -> $result // KILL $tmp" %}
- ins_encode %{
- __ array_equals(false, $str1$$Register, $str2$$Register,
- $cnt$$Register, $tmp$$Register,
- $result$$Register, false /* byte */);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct array_equalsB(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI result,
- o7RegI tmp2, flagsReg ccr) %{
- predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL);
- match(Set result (AryEq ary1 ary2));
- effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr);
- ins_cost(300);
- format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1,$tmp2" %}
- ins_encode %{
- __ array_equals(true, $ary1$$Register, $ary2$$Register,
- $tmp1$$Register, $tmp2$$Register,
- $result$$Register, true /* byte */);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct array_equalsC(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI result,
- o7RegI tmp2, flagsReg ccr) %{
- predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
- match(Set result (AryEq ary1 ary2));
- effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr);
- ins_cost(300);
- format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1,$tmp2" %}
- ins_encode %{
- __ array_equals(true, $ary1$$Register, $ary2$$Register,
- $tmp1$$Register, $tmp2$$Register,
- $result$$Register, false /* byte */);
- %}
- ins_pipe(long_memory_op);
-%}
-
-instruct has_negatives(o0RegP pAryR, g3RegI iSizeR, notemp_iRegI resultR,
- iRegL tmp1L, iRegL tmp2L, iRegL tmp3L, iRegL tmp4L,
- flagsReg ccr)
-%{
- match(Set resultR (HasNegatives pAryR iSizeR));
- effect(TEMP resultR, TEMP tmp1L, TEMP tmp2L, TEMP tmp3L, TEMP tmp4L, USE pAryR, USE iSizeR, KILL ccr);
- format %{ "has negatives byte[] $pAryR,$iSizeR -> $resultR // KILL $tmp1L,$tmp2L,$tmp3L,$tmp4L" %}
- ins_encode %{
- __ has_negatives($pAryR$$Register, $iSizeR$$Register,
- $resultR$$Register,
- $tmp1L$$Register, $tmp2L$$Register,
- $tmp3L$$Register, $tmp4L$$Register);
- %}
- ins_pipe(long_memory_op);
-%}
-
-// char[] to byte[] compression
-instruct string_compress(o0RegP src, o1RegP dst, g3RegI len, notemp_iRegI result, iRegL tmp, flagsReg ccr) %{
- predicate(UseVIS < 3);
- match(Set result (StrCompressedCopy src (Binary dst len)));
- effect(TEMP result, TEMP tmp, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr);
- ins_cost(300);
- format %{ "String Compress $src,$dst,$len -> $result // KILL $tmp" %}
- ins_encode %{
- Label Ldone;
- __ signx($len$$Register);
- __ cmp_zero_and_br(Assembler::zero, $len$$Register, Ldone, false, Assembler::pn);
- __ delayed()->mov($len$$Register, $result$$Register); // copy count
- __ string_compress($src$$Register, $dst$$Register, $len$$Register, $result$$Register, $tmp$$Register, Ldone);
- __ bind(Ldone);
- %}
- ins_pipe(long_memory_op);
-%}
-
-// fast char[] to byte[] compression using VIS instructions
-instruct string_compress_fast(o0RegP src, o1RegP dst, g3RegI len, notemp_iRegI result,
- iRegL tmp1, iRegL tmp2, iRegL tmp3, iRegL tmp4,
- regD ftmp1, regD ftmp2, regD ftmp3, flagsReg ccr) %{
- predicate(UseVIS >= 3);
- match(Set result (StrCompressedCopy src (Binary dst len)));
- effect(TEMP result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP ftmp1, TEMP ftmp2, TEMP ftmp3, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr);
- ins_cost(300);
- format %{ "String Compress Fast $src,$dst,$len -> $result // KILL $tmp1,$tmp2,$tmp3,$tmp4,$ftmp1,$ftmp2,$ftmp3" %}
- ins_encode %{
- Label Ldone;
- __ signx($len$$Register);
- __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $result$$Register,
- $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register,
- $ftmp1$$FloatRegister, $ftmp2$$FloatRegister, $ftmp3$$FloatRegister, Ldone);
- __ cmp_and_brx_short($len$$Register, 0, Assembler::equal, Assembler::pn, Ldone);
- __ string_compress($src$$Register, $dst$$Register, $len$$Register, $result$$Register, $tmp1$$Register, Ldone);
- __ bind(Ldone);
- %}
- ins_pipe(long_memory_op);
-%}
-
-// byte[] to char[] inflation
-instruct string_inflate(Universe dummy, o0RegP src, o1RegP dst, g3RegI len,
- iRegL tmp, flagsReg ccr) %{
- match(Set dummy (StrInflatedCopy src (Binary dst len)));
- effect(TEMP tmp, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr);
- ins_cost(300);
- format %{ "String Inflate $src,$dst,$len // KILL $tmp" %}
- ins_encode %{
- Label Ldone;
- __ signx($len$$Register);
- __ cmp_and_brx_short($len$$Register, 0, Assembler::equal, Assembler::pn, Ldone);
- __ string_inflate($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register, Ldone);
- __ bind(Ldone);
- %}
- ins_pipe(long_memory_op);
-%}
-
-// fast byte[] to char[] inflation using VIS instructions
-instruct string_inflate_fast(Universe dummy, o0RegP src, o1RegP dst, g3RegI len,
- iRegL tmp, regD ftmp1, regD ftmp2, regD ftmp3, regD ftmp4, flagsReg ccr) %{
- predicate(UseVIS >= 3);
- match(Set dummy (StrInflatedCopy src (Binary dst len)));
- effect(TEMP tmp, TEMP ftmp1, TEMP ftmp2, TEMP ftmp3, TEMP ftmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr);
- ins_cost(300);
- format %{ "String Inflate Fast $src,$dst,$len // KILL $tmp,$ftmp1,$ftmp2,$ftmp3,$ftmp4" %}
- ins_encode %{
- Label Ldone;
- __ signx($len$$Register);
- __ string_inflate_16($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register,
- $ftmp1$$FloatRegister, $ftmp2$$FloatRegister, $ftmp3$$FloatRegister, $ftmp4$$FloatRegister, Ldone);
- __ cmp_and_brx_short($len$$Register, 0, Assembler::equal, Assembler::pn, Ldone);
- __ string_inflate($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register, Ldone);
- __ bind(Ldone);
- %}
- ins_pipe(long_memory_op);
-%}
-
-
-//---------- Zeros Count Instructions ------------------------------------------
-
-instruct countLeadingZerosI(iRegIsafe dst, iRegI src, iRegI tmp, flagsReg cr) %{
- predicate(UsePopCountInstruction); // See Matcher::match_rule_supported
- match(Set dst (CountLeadingZerosI src));
- effect(TEMP dst, TEMP tmp, KILL cr);
-
- // x |= (x >> 1);
- // x |= (x >> 2);
- // x |= (x >> 4);
- // x |= (x >> 8);
- // x |= (x >> 16);
- // return (WORDBITS - popc(x));
- format %{ "SRL $src,1,$tmp\t! count leading zeros (int)\n\t"
- "SRL $src,0,$dst\t! 32-bit zero extend\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRL $dst,2,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRL $dst,4,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRL $dst,8,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRL $dst,16,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "POPC $dst,$dst\n\t"
- "MOV 32,$tmp\n\t"
- "SUB $tmp,$dst,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- __ srl(Rsrc, 1, Rtmp);
- __ srl(Rsrc, 0, Rdst);
- __ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 2, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 4, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 8, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ srl(Rdst, 16, Rtmp);
- __ or3(Rdst, Rtmp, Rdst);
- __ popc(Rdst, Rdst);
- __ mov(BitsPerInt, Rtmp);
- __ sub(Rtmp, Rdst, Rdst);
- %}
- ins_pipe(ialu_reg);
-%}
-
-instruct countLeadingZerosL(iRegIsafe dst, iRegL src, iRegL tmp, flagsReg cr) %{
- predicate(UsePopCountInstruction); // See Matcher::match_rule_supported
- match(Set dst (CountLeadingZerosL src));
- effect(TEMP dst, TEMP tmp, KILL cr);
-
- // x |= (x >> 1);
- // x |= (x >> 2);
- // x |= (x >> 4);
- // x |= (x >> 8);
- // x |= (x >> 16);
- // x |= (x >> 32);
- // return (WORDBITS - popc(x));
- format %{ "SRLX $src,1,$tmp\t! count leading zeros (long)\n\t"
- "OR $src,$tmp,$dst\n\t"
- "SRLX $dst,2,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRLX $dst,4,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRLX $dst,8,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRLX $dst,16,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "SRLX $dst,32,$tmp\n\t"
- "OR $dst,$tmp,$dst\n\t"
- "POPC $dst,$dst\n\t"
- "MOV 64,$tmp\n\t"
- "SUB $tmp,$dst,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- __ srlx(Rsrc, 1, Rtmp);
- __ or3( Rsrc, Rtmp, Rdst);
- __ srlx(Rdst, 2, Rtmp);
- __ or3( Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 4, Rtmp);
- __ or3( Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 8, Rtmp);
- __ or3( Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 16, Rtmp);
- __ or3( Rdst, Rtmp, Rdst);
- __ srlx(Rdst, 32, Rtmp);
- __ or3( Rdst, Rtmp, Rdst);
- __ popc(Rdst, Rdst);
- __ mov(BitsPerLong, Rtmp);
- __ sub(Rtmp, Rdst, Rdst);
- %}
- ins_pipe(ialu_reg);
-%}
-
-instruct countTrailingZerosI(iRegIsafe dst, iRegI src, flagsReg cr) %{
- predicate(UsePopCountInstruction); // See Matcher::match_rule_supported
- match(Set dst (CountTrailingZerosI src));
- effect(TEMP dst, KILL cr);
-
- // return popc(~x & (x - 1));
- format %{ "SUB $src,1,$dst\t! count trailing zeros (int)\n\t"
- "ANDN $dst,$src,$dst\n\t"
- "SRL $dst,R_G0,$dst\n\t"
- "POPC $dst,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- Register Rsrc = $src$$Register;
- __ sub(Rsrc, 1, Rdst);
- __ andn(Rdst, Rsrc, Rdst);
- __ srl(Rdst, G0, Rdst);
- __ popc(Rdst, Rdst);
- %}
- ins_pipe(ialu_reg);
-%}
-
-instruct countTrailingZerosL(iRegIsafe dst, iRegL src, flagsReg cr) %{
- predicate(UsePopCountInstruction); // See Matcher::match_rule_supported
- match(Set dst (CountTrailingZerosL src));
- effect(TEMP dst, KILL cr);
-
- // return popc(~x & (x - 1));
- format %{ "SUB $src,1,$dst\t! count trailing zeros (long)\n\t"
- "ANDN $dst,$src,$dst\n\t"
- "POPC $dst,$dst" %}
- ins_encode %{
- Register Rdst = $dst$$Register;
- Register Rsrc = $src$$Register;
- __ sub(Rsrc, 1, Rdst);
- __ andn(Rdst, Rsrc, Rdst);
- __ popc(Rdst, Rdst);
- %}
- ins_pipe(ialu_reg);
-%}
-
-
-//---------- Population Count Instructions -------------------------------------
-
-instruct popCountI(iRegIsafe dst, iRegI src) %{
- predicate(UsePopCountInstruction);
- match(Set dst (PopCountI src));
-
- format %{ "SRL $src, G0, $dst\t! clear upper word for 64 bit POPC\n\t"
- "POPC $dst, $dst" %}
- ins_encode %{
- __ srl($src$$Register, G0, $dst$$Register);
- __ popc($dst$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-// Note: Long.bitCount(long) returns an int.
-instruct popCountL(iRegIsafe dst, iRegL src) %{
- predicate(UsePopCountInstruction);
- match(Set dst (PopCountL src));
-
- format %{ "POPC $src, $dst" %}
- ins_encode %{
- __ popc($src$$Register, $dst$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-
-// ============================================================================
-//------------Bytes reverse--------------------------------------------------
-
-instruct bytes_reverse_int(iRegI dst, stackSlotI src) %{
- match(Set dst (ReverseBytesI src));
-
- // Op cost is artificially doubled to make sure that load or store
- // instructions are preferred over this one which requires a spill
- // onto a stack slot.
- ins_cost(2*DEFAULT_COST + MEMORY_REF_COST);
- format %{ "LDUWA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ set($src$$disp + STACK_BIAS, O7);
- __ lduwa($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe( iload_mem );
-%}
-
-instruct bytes_reverse_long(iRegL dst, stackSlotL src) %{
- match(Set dst (ReverseBytesL src));
-
- // Op cost is artificially doubled to make sure that load or store
- // instructions are preferred over this one which requires a spill
- // onto a stack slot.
- ins_cost(2*DEFAULT_COST + MEMORY_REF_COST);
- format %{ "LDXA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ set($src$$disp + STACK_BIAS, O7);
- __ ldxa($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe( iload_mem );
-%}
-
-instruct bytes_reverse_unsigned_short(iRegI dst, stackSlotI src) %{
- match(Set dst (ReverseBytesUS src));
-
- // Op cost is artificially doubled to make sure that load or store
- // instructions are preferred over this one which requires a spill
- // onto a stack slot.
- ins_cost(2*DEFAULT_COST + MEMORY_REF_COST);
- format %{ "LDUHA $src, $dst\t!asi=primary_little\n\t" %}
-
- ins_encode %{
- // the value was spilled as an int so bias the load
- __ set($src$$disp + STACK_BIAS + 2, O7);
- __ lduha($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe( iload_mem );
-%}
-
-instruct bytes_reverse_short(iRegI dst, stackSlotI src) %{
- match(Set dst (ReverseBytesS src));
-
- // Op cost is artificially doubled to make sure that load or store
- // instructions are preferred over this one which requires a spill
- // onto a stack slot.
- ins_cost(2*DEFAULT_COST + MEMORY_REF_COST);
- format %{ "LDSHA $src, $dst\t!asi=primary_little\n\t" %}
-
- ins_encode %{
- // the value was spilled as an int so bias the load
- __ set($src$$disp + STACK_BIAS + 2, O7);
- __ ldsha($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe( iload_mem );
-%}
-
-// Load Integer reversed byte order
-instruct loadI_reversed(iRegI dst, indIndexMemory src) %{
- match(Set dst (ReverseBytesI (LoadI src)));
-
- ins_cost(DEFAULT_COST + MEMORY_REF_COST);
- size(4);
- format %{ "LDUWA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ lduwa($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load Long - aligned and reversed
-instruct loadL_reversed(iRegL dst, indIndexMemory src) %{
- match(Set dst (ReverseBytesL (LoadL src)));
-
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "LDXA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ ldxa($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load unsigned short / char reversed byte order
-instruct loadUS_reversed(iRegI dst, indIndexMemory src) %{
- match(Set dst (ReverseBytesUS (LoadUS src)));
-
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "LDUHA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ lduha($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Load short reversed byte order
-instruct loadS_reversed(iRegI dst, indIndexMemory src) %{
- match(Set dst (ReverseBytesS (LoadS src)));
-
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "LDSHA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ ldsha($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register);
- %}
- ins_pipe(iload_mem);
-%}
-
-// Store Integer reversed byte order
-instruct storeI_reversed(indIndexMemory dst, iRegI src) %{
- match(Set dst (StoreI dst (ReverseBytesI src)));
-
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STWA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ stwa($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE);
- %}
- ins_pipe(istore_mem_reg);
-%}
-
-// Store Long reversed byte order
-instruct storeL_reversed(indIndexMemory dst, iRegL src) %{
- match(Set dst (StoreL dst (ReverseBytesL src)));
-
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STXA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ stxa($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE);
- %}
- ins_pipe(istore_mem_reg);
-%}
-
-// Store unsighed short/char reversed byte order
-instruct storeUS_reversed(indIndexMemory dst, iRegI src) %{
- match(Set dst (StoreC dst (ReverseBytesUS src)));
-
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STHA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ stha($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE);
- %}
- ins_pipe(istore_mem_reg);
-%}
-
-// Store short reversed byte order
-instruct storeS_reversed(indIndexMemory dst, iRegI src) %{
- match(Set dst (StoreC dst (ReverseBytesS src)));
-
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STHA $src, $dst\t!asi=primary_little" %}
-
- ins_encode %{
- __ stha($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE);
- %}
- ins_pipe(istore_mem_reg);
-%}
-
-// ====================VECTOR INSTRUCTIONS=====================================
-
-// Load Aligned Packed values into a Double Register
-instruct loadV8(regD dst, memory mem) %{
- predicate(n->as_LoadVector()->memory_size() == 8);
- match(Set dst (LoadVector mem));
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "LDDF $mem,$dst\t! load vector (8 bytes)" %}
- ins_encode %{
- __ ldf(FloatRegisterImpl::D, $mem$$Address, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(floadD_mem);
-%}
-
-// Store Vector in Double register to memory
-instruct storeV8(memory mem, regD src) %{
- predicate(n->as_StoreVector()->memory_size() == 8);
- match(Set mem (StoreVector mem src));
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STDF $src,$mem\t! store vector (8 bytes)" %}
- ins_encode %{
- __ stf(FloatRegisterImpl::D, as_DoubleFloatRegister($src$$reg), $mem$$Address);
- %}
- ins_pipe(fstoreD_mem_reg);
-%}
-
-// Store Zero into vector in memory
-instruct storeV8B_zero(memory mem, immI0 zero) %{
- predicate(n->as_StoreVector()->memory_size() == 8);
- match(Set mem (StoreVector mem (ReplicateB zero)));
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STX $zero,$mem\t! store zero vector (8 bytes)" %}
- ins_encode %{
- __ stx(G0, $mem$$Address);
- %}
- ins_pipe(fstoreD_mem_zero);
-%}
-
-instruct storeV4S_zero(memory mem, immI0 zero) %{
- predicate(n->as_StoreVector()->memory_size() == 8);
- match(Set mem (StoreVector mem (ReplicateS zero)));
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STX $zero,$mem\t! store zero vector (4 shorts)" %}
- ins_encode %{
- __ stx(G0, $mem$$Address);
- %}
- ins_pipe(fstoreD_mem_zero);
-%}
-
-instruct storeV2I_zero(memory mem, immI0 zero) %{
- predicate(n->as_StoreVector()->memory_size() == 8);
- match(Set mem (StoreVector mem (ReplicateI zero)));
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STX $zero,$mem\t! store zero vector (2 ints)" %}
- ins_encode %{
- __ stx(G0, $mem$$Address);
- %}
- ins_pipe(fstoreD_mem_zero);
-%}
-
-instruct storeV2F_zero(memory mem, immF0 zero) %{
- predicate(n->as_StoreVector()->memory_size() == 8);
- match(Set mem (StoreVector mem (ReplicateF zero)));
- ins_cost(MEMORY_REF_COST);
- size(4);
- format %{ "STX $zero,$mem\t! store zero vector (2 floats)" %}
- ins_encode %{
- __ stx(G0, $mem$$Address);
- %}
- ins_pipe(fstoreD_mem_zero);
-%}
-
-// Replicate scalar to packed byte values into Double register
-instruct Repl8B_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
- predicate(n->as_Vector()->length() == 8 && UseVIS >= 3);
- match(Set dst (ReplicateB src));
- effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
- format %{ "SLLX $src,56,$tmp\n\t"
- "SRLX $tmp, 8,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\n\t"
- "SRLX $tmp,16,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\n\t"
- "SRLX $tmp,32,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\t! replicate8B\n\t"
- "MOVXTOD $tmp,$dst\t! MoveL2D" %}
- ins_encode %{
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- Register Rtmp2 = $tmp2$$Register;
- __ sllx(Rsrc, 56, Rtmp);
- __ srlx(Rtmp, 8, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ srlx(Rtmp, 16, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ srlx(Rtmp, 32, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(ialu_reg);
-%}
-
-// Replicate scalar to packed byte values into Double stack
-instruct Repl8B_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
- predicate(n->as_Vector()->length() == 8 && UseVIS < 3);
- match(Set dst (ReplicateB src));
- effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
- format %{ "SLLX $src,56,$tmp\n\t"
- "SRLX $tmp, 8,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\n\t"
- "SRLX $tmp,16,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\n\t"
- "SRLX $tmp,32,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\t! replicate8B\n\t"
- "STX $tmp,$dst\t! regL to stkD" %}
- ins_encode %{
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- Register Rtmp2 = $tmp2$$Register;
- __ sllx(Rsrc, 56, Rtmp);
- __ srlx(Rtmp, 8, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ srlx(Rtmp, 16, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ srlx(Rtmp, 32, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ set ($dst$$disp + STACK_BIAS, Rtmp2);
- __ stx (Rtmp, Rtmp2, $dst$$base$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-// Replicate scalar constant to packed byte values in Double register
-instruct Repl8B_immI(regD dst, immI13 con, o7RegI tmp) %{
- predicate(n->as_Vector()->length() == 8);
- match(Set dst (ReplicateB con));
- effect(KILL tmp);
- format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %}
- ins_encode %{
- // XXX This is a quick fix for 6833573.
- //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister);
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 8, 1)), $tmp$$Register);
- __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(loadConFD);
-%}
-
-// Replicate scalar to packed char/short values into Double register
-instruct Repl4S_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
- predicate(n->as_Vector()->length() == 4 && UseVIS >= 3);
- match(Set dst (ReplicateS src));
- effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
- format %{ "SLLX $src,48,$tmp\n\t"
- "SRLX $tmp,16,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\n\t"
- "SRLX $tmp,32,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\t! replicate4S\n\t"
- "MOVXTOD $tmp,$dst\t! MoveL2D" %}
- ins_encode %{
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- Register Rtmp2 = $tmp2$$Register;
- __ sllx(Rsrc, 48, Rtmp);
- __ srlx(Rtmp, 16, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ srlx(Rtmp, 32, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(ialu_reg);
-%}
-
-// Replicate scalar to packed char/short values into Double stack
-instruct Repl4S_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
- predicate(n->as_Vector()->length() == 4 && UseVIS < 3);
- match(Set dst (ReplicateS src));
- effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
- format %{ "SLLX $src,48,$tmp\n\t"
- "SRLX $tmp,16,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\n\t"
- "SRLX $tmp,32,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\t! replicate4S\n\t"
- "STX $tmp,$dst\t! regL to stkD" %}
- ins_encode %{
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- Register Rtmp2 = $tmp2$$Register;
- __ sllx(Rsrc, 48, Rtmp);
- __ srlx(Rtmp, 16, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ srlx(Rtmp, 32, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ set ($dst$$disp + STACK_BIAS, Rtmp2);
- __ stx (Rtmp, Rtmp2, $dst$$base$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-// Replicate scalar constant to packed char/short values in Double register
-instruct Repl4S_immI(regD dst, immI con, o7RegI tmp) %{
- predicate(n->as_Vector()->length() == 4);
- match(Set dst (ReplicateS con));
- effect(KILL tmp);
- format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %}
- ins_encode %{
- // XXX This is a quick fix for 6833573.
- //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register);
- __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(loadConFD);
-%}
-
-// Replicate scalar to packed int values into Double register
-instruct Repl2I_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
- predicate(n->as_Vector()->length() == 2 && UseVIS >= 3);
- match(Set dst (ReplicateI src));
- effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
- format %{ "SLLX $src,32,$tmp\n\t"
- "SRLX $tmp,32,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\t! replicate2I\n\t"
- "MOVXTOD $tmp,$dst\t! MoveL2D" %}
- ins_encode %{
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- Register Rtmp2 = $tmp2$$Register;
- __ sllx(Rsrc, 32, Rtmp);
- __ srlx(Rtmp, 32, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(ialu_reg);
-%}
-
-// Replicate scalar to packed int values into Double stack
-instruct Repl2I_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
- predicate(n->as_Vector()->length() == 2 && UseVIS < 3);
- match(Set dst (ReplicateI src));
- effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
- format %{ "SLLX $src,32,$tmp\n\t"
- "SRLX $tmp,32,$tmp2\n\t"
- "OR $tmp,$tmp2,$tmp\t! replicate2I\n\t"
- "STX $tmp,$dst\t! regL to stkD" %}
- ins_encode %{
- Register Rsrc = $src$$Register;
- Register Rtmp = $tmp$$Register;
- Register Rtmp2 = $tmp2$$Register;
- __ sllx(Rsrc, 32, Rtmp);
- __ srlx(Rtmp, 32, Rtmp2);
- __ or3 (Rtmp, Rtmp2, Rtmp);
- __ set ($dst$$disp + STACK_BIAS, Rtmp2);
- __ stx (Rtmp, Rtmp2, $dst$$base$$Register);
- %}
- ins_pipe(ialu_reg);
-%}
-
-// Replicate scalar zero constant to packed int values in Double register
-instruct Repl2I_immI(regD dst, immI con, o7RegI tmp) %{
- predicate(n->as_Vector()->length() == 2);
- match(Set dst (ReplicateI con));
- effect(KILL tmp);
- format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %}
- ins_encode %{
- // XXX This is a quick fix for 6833573.
- //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister);
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 2, 4)), $tmp$$Register);
- __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(loadConFD);
-%}
-
-// Replicate scalar to packed float values into Double stack
-instruct Repl2F_stk(stackSlotD dst, regF src) %{
- predicate(n->as_Vector()->length() == 2);
- match(Set dst (ReplicateF src));
- ins_cost(MEMORY_REF_COST*2);
- format %{ "STF $src,$dst.hi\t! packed2F\n\t"
- "STF $src,$dst.lo" %}
- opcode(Assembler::stf_op3);
- ins_encode(simple_form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, src));
- ins_pipe(fstoreF_stk_reg);
-%}
-
-// Replicate scalar zero constant to packed float values in Double register
-instruct Repl2F_immF(regD dst, immF con, o7RegI tmp) %{
- predicate(n->as_Vector()->length() == 2);
- match(Set dst (ReplicateF con));
- effect(KILL tmp);
- format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2F($con)" %}
- ins_encode %{
- // XXX This is a quick fix for 6833573.
- //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immF($con$$constant)), $dst$$FloatRegister);
- RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immF($con$$constant)), $tmp$$Register);
- __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
- %}
- ins_pipe(loadConFD);
-%}
-
-//----------PEEPHOLE RULES-----------------------------------------------------
-// These must follow all instruction definitions as they use the names
-// defined in the instructions definitions.
-//
-// peepmatch ( root_instr_name [preceding_instruction]* );
-//
-// peepconstraint %{
-// (instruction_number.operand_name relational_op instruction_number.operand_name
-// [, ...] );
-// // instruction numbers are zero-based using left to right order in peepmatch
-//
-// peepreplace ( instr_name ( [instruction_number.operand_name]* ) );
-// // provide an instruction_number.operand_name for each operand that appears
-// // in the replacement instruction's match rule
-//
-// ---------VM FLAGS---------------------------------------------------------
-//
-// All peephole optimizations can be turned off using -XX:-OptoPeephole
-//
-// Each peephole rule is given an identifying number starting with zero and
-// increasing by one in the order seen by the parser. An individual peephole
-// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=#
-// on the command-line.
-//
-// ---------CURRENT LIMITATIONS----------------------------------------------
-//
-// Only match adjacent instructions in same basic block
-// Only equality constraints
-// Only constraints between operands, not (0.dest_reg == EAX_enc)
-// Only one replacement instruction
-//
-// ---------EXAMPLE----------------------------------------------------------
-//
-// // pertinent parts of existing instructions in architecture description
-// instruct movI(eRegI dst, eRegI src) %{
-// match(Set dst (CopyI src));
-// %}
-//
-// instruct incI_eReg(eRegI dst, immI1 src, eFlagsReg cr) %{
-// match(Set dst (AddI dst src));
-// effect(KILL cr);
-// %}
-//
-// // Change (inc mov) to lea
-// peephole %{
-// // increment preceeded by register-register move
-// peepmatch ( incI_eReg movI );
-// // require that the destination register of the increment
-// // match the destination register of the move
-// peepconstraint ( 0.dst == 1.dst );
-// // construct a replacement instruction that sets
-// // the destination to ( move's source register + one )
-// peepreplace ( incI_eReg_immI1( 0.dst 1.src 0.src ) );
-// %}
-//
-
-// // Change load of spilled value to only a spill
-// instruct storeI(memory mem, eRegI src) %{
-// match(Set mem (StoreI mem src));
-// %}
-//
-// instruct loadI(eRegI dst, memory mem) %{
-// match(Set dst (LoadI mem));
-// %}
-//
-// peephole %{
-// peepmatch ( loadI storeI );
-// peepconstraint ( 1.src == 0.dst, 1.mem == 0.mem );
-// peepreplace ( storeI( 1.mem 1.mem 1.src ) );
-// %}
-
-//----------SMARTSPILL RULES---------------------------------------------------
-// These must follow all instruction definitions as they use the names
-// defined in the instructions definitions.
-//
-// SPARC will probably not have any of these rules due to RISC instruction set.
-
-//----------PIPELINE-----------------------------------------------------------
-// Rules which define the behavior of the target architectures pipeline.
diff --git a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp b/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp
deleted file mode 100644
index 09a9fa32839..00000000000
--- a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp
+++ /dev/null
@@ -1,5875 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/barrierSet.hpp"
-#include "gc/shared/barrierSetAssembler.hpp"
-#include "interpreter/interpreter.hpp"
-#include "nativeInst_sparc.hpp"
-#include "oops/instanceOop.hpp"
-#include "oops/method.hpp"
-#include "oops/objArrayKlass.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/methodHandles.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubCodeGenerator.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/thread.inline.hpp"
-#ifdef COMPILER2
-#include "opto/runtime.hpp"
-#endif
-
-// Declaration and definition of StubGenerator (no .hpp file).
-// For a more detailed description of the stub routine structure
-// see the comment in stubRoutines.hpp.
-
-#define __ _masm->
-
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) /* nothing */
-#else
-#define BLOCK_COMMENT(str) __ block_comment(str)
-#endif
-
-#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
-
-// Note: The register L7 is used as L7_thread_cache, and may not be used
-// any other way within this module.
-
-static const Register& Lstub_temp = L2;
-
-// -------------------------------------------------------------------------------------------------------------------------
-// Stub Code definitions
-
-class StubGenerator: public StubCodeGenerator {
- private:
-
-#ifdef PRODUCT
-#define inc_counter_np(a,b,c)
-#else
-#define inc_counter_np(counter, t1, t2) \
- BLOCK_COMMENT("inc_counter " #counter); \
- __ inc_counter(&counter, t1, t2);
-#endif
-
- //----------------------------------------------------------------------------------------------------
- // Call stubs are used to call Java from C
-
- address generate_call_stub(address& return_pc) {
- StubCodeMark mark(this, "StubRoutines", "call_stub");
- address start = __ pc();
-
- // Incoming arguments:
- //
- // o0 : call wrapper address
- // o1 : result (address)
- // o2 : result type
- // o3 : method
- // o4 : (interpreter) entry point
- // o5 : parameters (address)
- // [sp + 0x5c]: parameter size (in words)
- // [sp + 0x60]: thread
- //
- // +---------------+ <--- sp + 0
- // | |
- // . reg save area .
- // | |
- // +---------------+ <--- sp + 0x40
- // | |
- // . extra 7 slots .
- // | |
- // +---------------+ <--- sp + 0x5c
- // | param. size |
- // +---------------+ <--- sp + 0x60
- // | thread |
- // +---------------+
- // | |
-
- // note: if the link argument position changes, adjust
- // the code in frame::entry_frame_call_wrapper()
-
- const Argument link = Argument(0, false); // used only for GC
- const Argument result = Argument(1, false);
- const Argument result_type = Argument(2, false);
- const Argument method = Argument(3, false);
- const Argument entry_point = Argument(4, false);
- const Argument parameters = Argument(5, false);
- const Argument parameter_size = Argument(6, false);
- const Argument thread = Argument(7, false);
-
- // setup thread register
- __ ld_ptr(thread.as_address(), G2_thread);
- __ reinit_heapbase();
-
-#ifdef ASSERT
- // make sure we have no pending exceptions
- { const Register t = G3_scratch;
- Label L;
- __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), t);
- __ br_null_short(t, Assembler::pt, L);
- __ stop("StubRoutines::call_stub: entered with pending exception");
- __ bind(L);
- }
-#endif
-
- // create activation frame & allocate space for parameters
- { const Register t = G3_scratch;
- __ ld_ptr(parameter_size.as_address(), t); // get parameter size (in words)
- __ add(t, frame::memory_parameter_word_sp_offset, t); // add space for save area (in words)
- __ round_to(t, WordsPerLong); // make sure it is multiple of 2 (in words)
- __ sll(t, Interpreter::logStackElementSize, t); // compute number of bytes
- __ neg(t); // negate so it can be used with save
- __ save(SP, t, SP); // setup new frame
- }
-
- // +---------------+ <--- sp + 0
- // | |
- // . reg save area .
- // | |
- // +---------------+ <--- sp + 0x40
- // | |
- // . extra 7 slots .
- // | |
- // +---------------+ <--- sp + 0x5c
- // | empty slot | (only if parameter size is even)
- // +---------------+
- // | |
- // . parameters .
- // | |
- // +---------------+ <--- fp + 0
- // | |
- // . reg save area .
- // | |
- // +---------------+ <--- fp + 0x40
- // | |
- // . extra 7 slots .
- // | |
- // +---------------+ <--- fp + 0x5c
- // | param. size |
- // +---------------+ <--- fp + 0x60
- // | thread |
- // +---------------+
- // | |
-
- // pass parameters if any
- BLOCK_COMMENT("pass parameters if any");
- { const Register src = parameters.as_in().as_register();
- const Register dst = Lentry_args;
- const Register tmp = G3_scratch;
- const Register cnt = G4_scratch;
-
- // test if any parameters & setup of Lentry_args
- Label exit;
- __ ld_ptr(parameter_size.as_in().as_address(), cnt); // parameter counter
- __ add( FP, STACK_BIAS, dst );
- __ cmp_zero_and_br(Assembler::zero, cnt, exit);
- __ delayed()->sub(dst, BytesPerWord, dst); // setup Lentry_args
-
- // copy parameters if any
- Label loop;
- __ BIND(loop);
- // Store parameter value
- __ ld_ptr(src, 0, tmp);
- __ add(src, BytesPerWord, src);
- __ st_ptr(tmp, dst, 0);
- __ deccc(cnt);
- __ br(Assembler::greater, false, Assembler::pt, loop);
- __ delayed()->sub(dst, Interpreter::stackElementSize, dst);
-
- // done
- __ BIND(exit);
- }
-
- // setup parameters, method & call Java function
-#ifdef ASSERT
- // layout_activation_impl checks it's notion of saved SP against
- // this register, so if this changes update it as well.
- const Register saved_SP = Lscratch;
- __ mov(SP, saved_SP); // keep track of SP before call
-#endif
-
- // setup parameters
- const Register t = G3_scratch;
- __ ld_ptr(parameter_size.as_in().as_address(), t); // get parameter size (in words)
- __ sll(t, Interpreter::logStackElementSize, t); // compute number of bytes
- __ sub(FP, t, Gargs); // setup parameter pointer
- __ add( Gargs, STACK_BIAS, Gargs ); // Account for LP64 stack bias
- __ mov(SP, O5_savedSP);
-
-
- // do the call
- //
- // the following register must be setup:
- //
- // G2_thread
- // G5_method
- // Gargs
- BLOCK_COMMENT("call Java function");
- __ jmpl(entry_point.as_in().as_register(), G0, O7);
- __ delayed()->mov(method.as_in().as_register(), G5_method); // setup method
-
- BLOCK_COMMENT("call_stub_return_address:");
- return_pc = __ pc();
-
- // The callee, if it wasn't interpreted, can return with SP changed so
- // we can no longer assert of change of SP.
-
- // store result depending on type
- // (everything that is not T_OBJECT, T_LONG, T_FLOAT, or T_DOUBLE
- // is treated as T_INT)
- { const Register addr = result .as_in().as_register();
- const Register type = result_type.as_in().as_register();
- Label is_long, is_float, is_double, is_object, exit;
- __ cmp(type, T_OBJECT); __ br(Assembler::equal, false, Assembler::pn, is_object);
- __ delayed()->cmp(type, T_FLOAT); __ br(Assembler::equal, false, Assembler::pn, is_float);
- __ delayed()->cmp(type, T_DOUBLE); __ br(Assembler::equal, false, Assembler::pn, is_double);
- __ delayed()->cmp(type, T_LONG); __ br(Assembler::equal, false, Assembler::pn, is_long);
- __ delayed()->nop();
-
- // store int result
- __ st(O0, addr, G0);
-
- __ BIND(exit);
- __ ret();
- __ delayed()->restore();
-
- __ BIND(is_object);
- __ ba(exit);
- __ delayed()->st_ptr(O0, addr, G0);
-
- __ BIND(is_float);
- __ ba(exit);
- __ delayed()->stf(FloatRegisterImpl::S, F0, addr, G0);
-
- __ BIND(is_double);
- __ ba(exit);
- __ delayed()->stf(FloatRegisterImpl::D, F0, addr, G0);
-
- __ BIND(is_long);
- __ ba(exit);
- __ delayed()->st_long(O0, addr, G0); // store entire long
- }
- return start;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Return point for a Java call if there's an exception thrown in Java code.
- // The exception is caught and transformed into a pending exception stored in
- // JavaThread that can be tested from within the VM.
- //
- // Oexception: exception oop
-
- address generate_catch_exception() {
- StubCodeMark mark(this, "StubRoutines", "catch_exception");
-
- address start = __ pc();
- // verify that thread corresponds
- __ verify_thread();
-
- const Register& temp_reg = Gtemp;
- Address pending_exception_addr (G2_thread, Thread::pending_exception_offset());
- Address exception_file_offset_addr(G2_thread, Thread::exception_file_offset ());
- Address exception_line_offset_addr(G2_thread, Thread::exception_line_offset ());
-
- // set pending exception
- __ verify_oop(Oexception);
- __ st_ptr(Oexception, pending_exception_addr);
- __ set((intptr_t)__FILE__, temp_reg);
- __ st_ptr(temp_reg, exception_file_offset_addr);
- __ set((intptr_t)__LINE__, temp_reg);
- __ st(temp_reg, exception_line_offset_addr);
-
- // complete return to VM
- assert(StubRoutines::_call_stub_return_address != NULL, "must have been generated before");
-
- AddressLiteral stub_ret(StubRoutines::_call_stub_return_address);
- __ jump_to(stub_ret, temp_reg);
- __ delayed()->nop();
-
- return start;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Continuation point for runtime calls returning with a pending exception
- // The pending exception check happened in the runtime or native call stub
- // The pending exception in Thread is converted into a Java-level exception
- //
- // Contract with Java-level exception handler: O0 = exception
- // O1 = throwing pc
-
- address generate_forward_exception() {
- StubCodeMark mark(this, "StubRoutines", "forward_exception");
- address start = __ pc();
-
- // Upon entry, O7 has the return address returning into Java
- // (interpreted or compiled) code; i.e. the return address
- // becomes the throwing pc.
-
- const Register& handler_reg = Gtemp;
-
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
-
-#ifdef ASSERT
- // make sure that this code is only executed if there is a pending exception
- { Label L;
- __ ld_ptr(exception_addr, Gtemp);
- __ br_notnull_short(Gtemp, Assembler::pt, L);
- __ stop("StubRoutines::forward exception: no pending exception (1)");
- __ bind(L);
- }
-#endif
-
- // compute exception handler into handler_reg
- __ get_thread();
- __ ld_ptr(exception_addr, Oexception);
- __ verify_oop(Oexception);
- __ save_frame(0); // compensates for compiler weakness
- __ add(O7->after_save(), frame::pc_return_offset, Lscratch); // save the issuing PC
- BLOCK_COMMENT("call exception_handler_for_return_address");
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), G2_thread, Lscratch);
- __ mov(O0, handler_reg);
- __ restore(); // compensates for compiler weakness
-
- __ ld_ptr(exception_addr, Oexception);
- __ add(O7, frame::pc_return_offset, Oissuing_pc); // save the issuing PC
-
-#ifdef ASSERT
- // make sure exception is set
- { Label L;
- __ br_notnull_short(Oexception, Assembler::pt, L);
- __ stop("StubRoutines::forward exception: no pending exception (2)");
- __ bind(L);
- }
-#endif
- // jump to exception handler
- __ jmp(handler_reg, 0);
- // clear pending exception
- __ delayed()->st_ptr(G0, exception_addr);
-
- return start;
- }
-
- // Safefetch stubs.
- void generate_safefetch(const char* name, int size, address* entry,
- address* fault_pc, address* continuation_pc) {
- // safefetch signatures:
- // int SafeFetch32(int* adr, int errValue);
- // intptr_t SafeFetchN (intptr_t* adr, intptr_t errValue);
- //
- // arguments:
- // o0 = adr
- // o1 = errValue
- //
- // result:
- // o0 = *adr or errValue
-
- StubCodeMark mark(this, "StubRoutines", name);
-
- // Entry point, pc or function descriptor.
- __ align(CodeEntryAlignment);
- *entry = __ pc();
-
- __ mov(O0, G1); // g1 = o0
- __ mov(O1, O0); // o0 = o1
- // Load *adr into c_rarg1, may fault.
- *fault_pc = __ pc();
- switch (size) {
- case 4:
- // int32_t
- __ ldsw(G1, 0, O0); // o0 = [g1]
- break;
- case 8:
- // int64_t
- __ ldx(G1, 0, O0); // o0 = [g1]
- break;
- default:
- ShouldNotReachHere();
- }
-
- // return errValue or *adr
- *continuation_pc = __ pc();
- // By convention with the trap handler we ensure there is a non-CTI
- // instruction in the trap shadow.
- __ nop();
- __ retl();
- __ delayed()->nop();
- }
-
- //------------------------------------------------------------------------------------------------------------------------
- // Continuation point for throwing of implicit exceptions that are not handled in
- // the current activation. Fabricates an exception oop and initiates normal
- // exception dispatching in this frame. Only callee-saved registers are preserved
- // (through the normal register window / RegisterMap handling).
- // If the compiler needs all registers to be preserved between the fault
- // point and the exception handler then it must assume responsibility for that in
- // AbstractCompiler::continuation_for_implicit_null_exception or
- // continuation_for_implicit_division_by_zero_exception. All other implicit
- // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are
- // either at call sites or otherwise assume that stack unwinding will be initiated,
- // so caller saved registers were assumed volatile in the compiler.
-
- // Note that we generate only this stub into a RuntimeStub, because it needs to be
- // properly traversed and ignored during GC, so we change the meaning of the "__"
- // macro within this method.
-#undef __
-#define __ masm->
-
- address generate_throw_exception(const char* name, address runtime_entry,
- Register arg1 = noreg, Register arg2 = noreg) {
-#ifdef ASSERT
- int insts_size = VerifyThread ? 1 * K : 600;
-#else
- int insts_size = VerifyThread ? 1 * K : 256;
-#endif /* ASSERT */
- int locs_size = 32;
-
- CodeBuffer code(name, insts_size, locs_size);
- MacroAssembler* masm = new MacroAssembler(&code);
-
- __ verify_thread();
-
- // This is an inlined and slightly modified version of call_VM
- // which has the ability to fetch the return PC out of thread-local storage
- __ assert_not_delayed();
-
- // Note that we always push a frame because on the SPARC
- // architecture, for all of our implicit exception kinds at call
- // sites, the implicit exception is taken before the callee frame
- // is pushed.
- __ save_frame(0);
-
- int frame_complete = __ offset();
-
- // Note that we always have a runtime stub frame on the top of stack by this point
- Register last_java_sp = SP;
- // 64-bit last_java_sp is biased!
- __ set_last_Java_frame(last_java_sp, G0);
- if (VerifyThread) __ mov(G2_thread, O0); // about to be smashed; pass early
- __ save_thread(noreg);
- if (arg1 != noreg) {
- assert(arg2 != O1, "clobbered");
- __ mov(arg1, O1);
- }
- if (arg2 != noreg) {
- __ mov(arg2, O2);
- }
- // do the call
- BLOCK_COMMENT("call runtime_entry");
- __ call(runtime_entry, relocInfo::runtime_call_type);
- if (!VerifyThread)
- __ delayed()->mov(G2_thread, O0); // pass thread as first argument
- else
- __ delayed()->nop(); // (thread already passed)
- __ restore_thread(noreg);
- __ reset_last_Java_frame();
-
- // check for pending exceptions. use Gtemp as scratch register.
-#ifdef ASSERT
- Label L;
-
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- Register scratch_reg = Gtemp;
- __ ld_ptr(exception_addr, scratch_reg);
- __ br_notnull_short(scratch_reg, Assembler::pt, L);
- __ should_not_reach_here();
- __ bind(L);
-#endif // ASSERT
- BLOCK_COMMENT("call forward_exception_entry");
- __ call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type);
- // we use O7 linkage so that forward_exception_entry has the issuing PC
- __ delayed()->restore();
-
- RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, masm->total_frame_size_in_bytes(0), NULL, false);
- return stub->entry_point();
- }
-
-#undef __
-#define __ _masm->
-
-
- // Generate a routine that sets all the registers so we
- // can tell if the stop routine prints them correctly.
- address generate_test_stop() {
- StubCodeMark mark(this, "StubRoutines", "test_stop");
- address start = __ pc();
-
- int i;
-
- __ save_frame(0);
-
- static jfloat zero = 0.0, one = 1.0;
-
- // put addr in L0, then load through L0 to F0
- __ set((intptr_t)&zero, L0); __ ldf( FloatRegisterImpl::S, L0, 0, F0);
- __ set((intptr_t)&one, L0); __ ldf( FloatRegisterImpl::S, L0, 0, F1); // 1.0 to F1
-
- // use add to put 2..18 in F2..F18
- for ( i = 2; i <= 18; ++i ) {
- __ fadd( FloatRegisterImpl::S, F1, as_FloatRegister(i-1), as_FloatRegister(i));
- }
-
- // Now put double 2 in F16, double 18 in F18
- __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, F2, F16 );
- __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, F18, F18 );
-
- // use add to put 20..32 in F20..F32
- for (i = 20; i < 32; i += 2) {
- __ fadd( FloatRegisterImpl::D, F16, as_FloatRegister(i-2), as_FloatRegister(i));
- }
-
- // put 0..7 in i's, 8..15 in l's, 16..23 in o's, 24..31 in g's
- for ( i = 0; i < 8; ++i ) {
- if (i < 6) {
- __ set( i, as_iRegister(i));
- __ set(16 + i, as_oRegister(i));
- __ set(24 + i, as_gRegister(i));
- }
- __ set( 8 + i, as_lRegister(i));
- }
-
- __ stop("testing stop");
-
-
- __ ret();
- __ delayed()->restore();
-
- return start;
- }
-
-
- address generate_stop_subroutine() {
- StubCodeMark mark(this, "StubRoutines", "stop_subroutine");
- address start = __ pc();
-
- __ stop_subroutine();
-
- return start;
- }
-
- address generate_flush_callers_register_windows() {
- StubCodeMark mark(this, "StubRoutines", "flush_callers_register_windows");
- address start = __ pc();
-
- __ flushw();
- __ retl(false);
- __ delayed()->add( FP, STACK_BIAS, O0 );
- // The returned value must be a stack pointer whose register save area
- // is flushed, and will stay flushed while the caller executes.
-
- return start;
- }
-
- // Implementation of jint atomic_xchg(jint exchange_value, volatile jint* dest)
- // used by Atomic::xchg(volatile jint* dest, jint exchange_value)
- //
- // Arguments:
- //
- // exchange_value: O0
- // dest: O1
- //
- // Results:
- //
- // O0: the value previously stored in dest
- //
- address generate_atomic_xchg() {
- StubCodeMark mark(this, "StubRoutines", "atomic_xchg");
- address start = __ pc();
-
- if (UseCASForSwap) {
- // Use CAS instead of swap, just in case the MP hardware
- // prefers to work with just one kind of synch. instruction.
- Label retry;
- __ BIND(retry);
- __ mov(O0, O3); // scratch copy of exchange value
- __ ld(O1, 0, O2); // observe the previous value
- // try to replace O2 with O3
- __ cas(O1, O2, O3);
- __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pn, retry);
-
- __ retl(false);
- __ delayed()->mov(O2, O0); // report previous value to caller
- } else {
- __ retl(false);
- __ delayed()->swap(O1, 0, O0);
- }
-
- return start;
- }
-
-
- // Implementation of jint atomic_cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value)
- // used by Atomic::cmpxchg(volatile jint* dest, jint compare_value, jint exchange_value)
- //
- // Arguments:
- //
- // exchange_value: O0
- // dest: O1
- // compare_value: O2
- //
- // Results:
- //
- // O0: the value previously stored in dest
- //
- address generate_atomic_cmpxchg() {
- StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg");
- address start = __ pc();
-
- // cmpxchg(dest, compare_value, exchange_value)
- __ cas(O1, O2, O0);
- __ retl(false);
- __ delayed()->nop();
-
- return start;
- }
-
- // Implementation of jlong atomic_cmpxchg_long(jlong exchange_value, volatile jlong *dest, jlong compare_value)
- // used by Atomic::cmpxchg(volatile jlong *dest, jlong compare_value, jlong exchange_value)
- //
- // Arguments:
- //
- // exchange_value: O1:O0
- // dest: O2
- // compare_value: O4:O3
- //
- // Results:
- //
- // O1:O0: the value previously stored in dest
- //
- // Overwrites: G1,G2,G3
- //
- address generate_atomic_cmpxchg_long() {
- StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg_long");
- address start = __ pc();
-
- __ sllx(O0, 32, O0);
- __ srl(O1, 0, O1);
- __ or3(O0,O1,O0); // O0 holds 64-bit value from compare_value
- __ sllx(O3, 32, O3);
- __ srl(O4, 0, O4);
- __ or3(O3,O4,O3); // O3 holds 64-bit value from exchange_value
- __ casx(O2, O3, O0);
- __ srl(O0, 0, O1); // unpacked return value in O1:O0
- __ retl(false);
- __ delayed()->srlx(O0, 32, O0);
-
- return start;
- }
-
-
- // Implementation of jint atomic_add(jint add_value, volatile jint* dest)
- // used by Atomic::add(volatile jint* dest, jint add_value)
- //
- // Arguments:
- //
- // add_value: O0 (e.g., +1 or -1)
- // dest: O1
- //
- // Results:
- //
- // O0: the new value stored in dest
- //
- // Overwrites: O3
- //
- address generate_atomic_add() {
- StubCodeMark mark(this, "StubRoutines", "atomic_add");
- address start = __ pc();
- __ BIND(_atomic_add_stub);
-
- Label(retry);
- __ BIND(retry);
-
- __ lduw(O1, 0, O2);
- __ add(O0, O2, O3);
- __ cas(O1, O2, O3);
- __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pn, retry);
- __ retl(false);
- __ delayed()->add(O0, O2, O0); // note that cas made O2==O3
-
- return start;
- }
- Label _atomic_add_stub; // called from other stubs
-
-
- // Support for uint StubRoutine::Sparc::partial_subtype_check( Klass sub, Klass super );
- // Arguments :
- //
- // ret : O0, returned
- // icc/xcc: set as O0 (depending on wordSize)
- // sub : O1, argument, not changed
- // super: O2, argument, not changed
- // raddr: O7, blown by call
- address generate_partial_subtype_check() {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "partial_subtype_check");
- address start = __ pc();
- Label miss;
-
- __ save_frame(0);
- Register Rret = I0;
- Register Rsub = I1;
- Register Rsuper = I2;
-
- Register L0_ary_len = L0;
- Register L1_ary_ptr = L1;
- Register L2_super = L2;
- Register L3_index = L3;
-
- __ check_klass_subtype_slow_path(Rsub, Rsuper,
- L0, L1, L2, L3,
- NULL, &miss);
-
- // Match falls through here.
- __ addcc(G0,0,Rret); // set Z flags, Z result
-
- __ ret(); // Result in Rret is zero; flags set to Z
- __ delayed()->restore();
-
- __ BIND(miss);
- __ addcc(G0,1,Rret); // set NZ flags, NZ result
-
- __ ret(); // Result in Rret is != 0; flags set to NZ
- __ delayed()->restore();
-
- return start;
- }
-
-
- // Called from MacroAssembler::verify_oop
- //
- address generate_verify_oop_subroutine() {
- StubCodeMark mark(this, "StubRoutines", "verify_oop_stub");
-
- address start = __ pc();
-
- __ verify_oop_subroutine();
-
- return start;
- }
-
-
- //
- // Verify that a register contains clean 32-bits positive value
- // (high 32-bits are 0) so it could be used in 64-bits shifts (sllx, srax).
- //
- // Input:
- // Rint - 32-bits value
- // Rtmp - scratch
- //
- void assert_clean_int(Register Rint, Register Rtmp) {
- #if defined(ASSERT)
- __ signx(Rint, Rtmp);
- __ cmp(Rint, Rtmp);
- __ breakpoint_trap(Assembler::notEqual, Assembler::xcc);
- #endif
- }
-
- //
- // Generate overlap test for array copy stubs
- //
- // Input:
- // O0 - array1
- // O1 - array2
- // O2 - element count
- //
- // Kills temps: O3, O4
- //
- void array_overlap_test(address no_overlap_target, int log2_elem_size) {
- assert(no_overlap_target != NULL, "must be generated");
- array_overlap_test(no_overlap_target, NULL, log2_elem_size);
- }
- void array_overlap_test(Label& L_no_overlap, int log2_elem_size) {
- array_overlap_test(NULL, &L_no_overlap, log2_elem_size);
- }
- void array_overlap_test(address no_overlap_target, Label* NOLp, int log2_elem_size) {
- const Register from = O0;
- const Register to = O1;
- const Register count = O2;
- const Register to_from = O3; // to - from
- const Register byte_count = O4; // count << log2_elem_size
-
- __ subcc(to, from, to_from);
- __ sll_ptr(count, log2_elem_size, byte_count);
- if (NOLp == NULL)
- __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, no_overlap_target);
- else
- __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, (*NOLp));
- __ delayed()->cmp(to_from, byte_count);
- if (NOLp == NULL)
- __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, no_overlap_target);
- else
- __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, (*NOLp));
- __ delayed()->nop();
- }
-
-
- //
- // Generate main code for disjoint arraycopy
- //
- typedef void (StubGenerator::*CopyLoopFunc)(Register from, Register to, Register count, int count_dec,
- Label& L_loop, bool use_prefetch, bool use_bis);
-
- void disjoint_copy_core(Register from, Register to, Register count, int log2_elem_size,
- int iter_size, StubGenerator::CopyLoopFunc copy_loop_func) {
- Label L_copy;
-
- assert(log2_elem_size <= 3, "the following code should be changed");
- int count_dec = 16>>log2_elem_size;
-
- int prefetch_dist = MAX2(ArraycopySrcPrefetchDistance, ArraycopyDstPrefetchDistance);
- assert(prefetch_dist < 4096, "invalid value");
- prefetch_dist = (prefetch_dist + (iter_size-1)) & (-iter_size); // round up to one iteration copy size
- int prefetch_count = (prefetch_dist >> log2_elem_size); // elements count
-
- if (UseBlockCopy) {
- Label L_block_copy, L_block_copy_prefetch, L_skip_block_copy;
-
- // 64 bytes tail + bytes copied in one loop iteration
- int tail_size = 64 + iter_size;
- int block_copy_count = (MAX2(tail_size, (int)BlockCopyLowLimit)) >> log2_elem_size;
- // Use BIS copy only for big arrays since it requires membar.
- __ set(block_copy_count, O4);
- __ cmp_and_br_short(count, O4, Assembler::lessUnsigned, Assembler::pt, L_skip_block_copy);
- // This code is for disjoint source and destination:
- // to <= from || to >= from+count
- // but BIS will stomp over 'from' if (to > from-tail_size && to <= from)
- __ sub(from, to, O4);
- __ srax(O4, 4, O4); // divide by 16 since following short branch have only 5 bits for imm.
- __ cmp_and_br_short(O4, (tail_size>>4), Assembler::lessEqualUnsigned, Assembler::pn, L_skip_block_copy);
-
- __ wrasi(G0, Assembler::ASI_ST_BLKINIT_PRIMARY);
- // BIS should not be used to copy tail (64 bytes+iter_size)
- // to avoid zeroing of following values.
- __ sub(count, (tail_size>>log2_elem_size), count); // count is still positive >= 0
-
- if (prefetch_count > 0) { // rounded up to one iteration count
- // Do prefetching only if copy size is bigger
- // than prefetch distance.
- __ set(prefetch_count, O4);
- __ cmp_and_brx_short(count, O4, Assembler::less, Assembler::pt, L_block_copy);
- __ sub(count, O4, count);
-
- (this->*copy_loop_func)(from, to, count, count_dec, L_block_copy_prefetch, true, true);
- __ set(prefetch_count, O4);
- __ add(count, O4, count);
-
- } // prefetch_count > 0
-
- (this->*copy_loop_func)(from, to, count, count_dec, L_block_copy, false, true);
- __ add(count, (tail_size>>log2_elem_size), count); // restore count
-
- __ wrasi(G0, Assembler::ASI_PRIMARY_NOFAULT);
- // BIS needs membar.
- __ membar(Assembler::StoreLoad);
- // Copy tail
- __ ba_short(L_copy);
-
- __ BIND(L_skip_block_copy);
- } // UseBlockCopy
-
- if (prefetch_count > 0) { // rounded up to one iteration count
- // Do prefetching only if copy size is bigger
- // than prefetch distance.
- __ set(prefetch_count, O4);
- __ cmp_and_brx_short(count, O4, Assembler::lessUnsigned, Assembler::pt, L_copy);
- __ sub(count, O4, count);
-
- Label L_copy_prefetch;
- (this->*copy_loop_func)(from, to, count, count_dec, L_copy_prefetch, true, false);
- __ set(prefetch_count, O4);
- __ add(count, O4, count);
-
- } // prefetch_count > 0
-
- (this->*copy_loop_func)(from, to, count, count_dec, L_copy, false, false);
- }
-
-
-
- //
- // Helper methods for copy_16_bytes_forward_with_shift()
- //
- void copy_16_bytes_shift_loop(Register from, Register to, Register count, int count_dec,
- Label& L_loop, bool use_prefetch, bool use_bis) {
-
- const Register left_shift = G1; // left shift bit counter
- const Register right_shift = G5; // right shift bit counter
-
- __ align(OptoLoopAlignment);
- __ BIND(L_loop);
- if (use_prefetch) {
- if (ArraycopySrcPrefetchDistance > 0) {
- __ prefetch(from, ArraycopySrcPrefetchDistance, Assembler::severalReads);
- }
- if (ArraycopyDstPrefetchDistance > 0) {
- __ prefetch(to, ArraycopyDstPrefetchDistance, Assembler::severalWritesAndPossiblyReads);
- }
- }
- __ ldx(from, 0, O4);
- __ ldx(from, 8, G4);
- __ inc(to, 16);
- __ inc(from, 16);
- __ deccc(count, count_dec); // Can we do next iteration after this one?
- __ srlx(O4, right_shift, G3);
- __ bset(G3, O3);
- __ sllx(O4, left_shift, O4);
- __ srlx(G4, right_shift, G3);
- __ bset(G3, O4);
- if (use_bis) {
- __ stxa(O3, to, -16);
- __ stxa(O4, to, -8);
- } else {
- __ stx(O3, to, -16);
- __ stx(O4, to, -8);
- }
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
- __ delayed()->sllx(G4, left_shift, O3);
- }
-
- // Copy big chunks forward with shift
- //
- // Inputs:
- // from - source arrays
- // to - destination array aligned to 8-bytes
- // count - elements count to copy >= the count equivalent to 16 bytes
- // count_dec - elements count's decrement equivalent to 16 bytes
- // L_copy_bytes - copy exit label
- //
- void copy_16_bytes_forward_with_shift(Register from, Register to,
- Register count, int log2_elem_size, Label& L_copy_bytes) {
- Label L_aligned_copy, L_copy_last_bytes;
- assert(log2_elem_size <= 3, "the following code should be changed");
- int count_dec = 16>>log2_elem_size;
-
- // if both arrays have the same alignment mod 8, do 8 bytes aligned copy
- __ andcc(from, 7, G1); // misaligned bytes
- __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy);
- __ delayed()->nop();
-
- const Register left_shift = G1; // left shift bit counter
- const Register right_shift = G5; // right shift bit counter
-
- __ sll(G1, LogBitsPerByte, left_shift);
- __ mov(64, right_shift);
- __ sub(right_shift, left_shift, right_shift);
-
- //
- // Load 2 aligned 8-bytes chunks and use one from previous iteration
- // to form 2 aligned 8-bytes chunks to store.
- //
- __ dec(count, count_dec); // Pre-decrement 'count'
- __ andn(from, 7, from); // Align address
- __ ldx(from, 0, O3);
- __ inc(from, 8);
- __ sllx(O3, left_shift, O3);
-
- disjoint_copy_core(from, to, count, log2_elem_size, 16, &StubGenerator::copy_16_bytes_shift_loop);
-
- __ inccc(count, count_dec>>1 ); // + 8 bytes
- __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes);
- __ delayed()->inc(count, count_dec>>1); // restore 'count'
-
- // copy 8 bytes, part of them already loaded in O3
- __ ldx(from, 0, O4);
- __ inc(to, 8);
- __ inc(from, 8);
- __ srlx(O4, right_shift, G3);
- __ bset(O3, G3);
- __ stx(G3, to, -8);
-
- __ BIND(L_copy_last_bytes);
- __ srl(right_shift, LogBitsPerByte, right_shift); // misaligned bytes
- __ br(Assembler::always, false, Assembler::pt, L_copy_bytes);
- __ delayed()->sub(from, right_shift, from); // restore address
-
- __ BIND(L_aligned_copy);
- }
-
- // Copy big chunks backward with shift
- //
- // Inputs:
- // end_from - source arrays end address
- // end_to - destination array end address aligned to 8-bytes
- // count - elements count to copy >= the count equivalent to 16 bytes
- // count_dec - elements count's decrement equivalent to 16 bytes
- // L_aligned_copy - aligned copy exit label
- // L_copy_bytes - copy exit label
- //
- void copy_16_bytes_backward_with_shift(Register end_from, Register end_to,
- Register count, int count_dec,
- Label& L_aligned_copy, Label& L_copy_bytes) {
- Label L_loop, L_copy_last_bytes;
-
- // if both arrays have the same alignment mod 8, do 8 bytes aligned copy
- __ andcc(end_from, 7, G1); // misaligned bytes
- __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy);
- __ delayed()->deccc(count, count_dec); // Pre-decrement 'count'
-
- const Register left_shift = G1; // left shift bit counter
- const Register right_shift = G5; // right shift bit counter
-
- __ sll(G1, LogBitsPerByte, left_shift);
- __ mov(64, right_shift);
- __ sub(right_shift, left_shift, right_shift);
-
- //
- // Load 2 aligned 8-bytes chunks and use one from previous iteration
- // to form 2 aligned 8-bytes chunks to store.
- //
- __ andn(end_from, 7, end_from); // Align address
- __ ldx(end_from, 0, O3);
- __ align(OptoLoopAlignment);
- __ BIND(L_loop);
- __ ldx(end_from, -8, O4);
- __ deccc(count, count_dec); // Can we do next iteration after this one?
- __ ldx(end_from, -16, G4);
- __ dec(end_to, 16);
- __ dec(end_from, 16);
- __ srlx(O3, right_shift, O3);
- __ sllx(O4, left_shift, G3);
- __ bset(G3, O3);
- __ stx(O3, end_to, 8);
- __ srlx(O4, right_shift, O4);
- __ sllx(G4, left_shift, G3);
- __ bset(G3, O4);
- __ stx(O4, end_to, 0);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
- __ delayed()->mov(G4, O3);
-
- __ inccc(count, count_dec>>1 ); // + 8 bytes
- __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes);
- __ delayed()->inc(count, count_dec>>1); // restore 'count'
-
- // copy 8 bytes, part of them already loaded in O3
- __ ldx(end_from, -8, O4);
- __ dec(end_to, 8);
- __ dec(end_from, 8);
- __ srlx(O3, right_shift, O3);
- __ sllx(O4, left_shift, G3);
- __ bset(O3, G3);
- __ stx(G3, end_to, 0);
-
- __ BIND(L_copy_last_bytes);
- __ srl(left_shift, LogBitsPerByte, left_shift); // misaligned bytes
- __ br(Assembler::always, false, Assembler::pt, L_copy_bytes);
- __ delayed()->add(end_from, left_shift, end_from); // restore address
- }
-
- address generate_unsafecopy_common_error_exit() {
- address start_pc = __ pc();
- if (UseBlockCopy) {
- __ wrasi(G0, Assembler::ASI_PRIMARY_NOFAULT);
- __ membar(Assembler::StoreLoad);
- }
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start_pc;
- }
-
- //
- // Generate stub for disjoint byte copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_disjoint_byte_copy(bool aligned, address *entry, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- Label L_skip_alignment, L_align;
- Label L_copy_byte, L_copy_byte_loop, L_exit;
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register offset = O5; // offset from start of arrays
- // O3, O4, G3, G4 are used as temp registers
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
-
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, !aligned, false);
-
- // for short arrays, just do single element copy
- __ cmp(count, 23); // 16 + 7
- __ brx(Assembler::less, false, Assembler::pn, L_copy_byte);
- __ delayed()->mov(G0, offset);
-
- if (aligned) {
- // 'aligned' == true when it is known statically during compilation
- // of this arraycopy call site that both 'from' and 'to' addresses
- // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()).
- //
- // Aligned arrays have 4 bytes alignment in 32-bits VM
- // and 8 bytes - in 64-bits VM. So we do it only for 32-bits VM
- //
- } else {
- // copy bytes to align 'to' on 8 byte boundary
- __ andcc(to, 7, G1); // misaligned bytes
- __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment);
- __ delayed()->neg(G1);
- __ inc(G1, 8); // bytes need to copy to next 8-bytes alignment
- __ sub(count, G1, count);
- __ BIND(L_align);
- __ ldub(from, 0, O3);
- __ deccc(G1);
- __ inc(from);
- __ stb(O3, to, 0);
- __ br(Assembler::notZero, false, Assembler::pt, L_align);
- __ delayed()->inc(to);
- __ BIND(L_skip_alignment);
- }
- if (!aligned) {
- // Copy with shift 16 bytes per iteration if arrays do not have
- // the same alignment mod 8, otherwise fall through to the next
- // code for aligned copy.
- // The compare above (count >= 23) guarantes 'count' >= 16 bytes.
- // Also jump over aligned copy after the copy with shift completed.
-
- copy_16_bytes_forward_with_shift(from, to, count, 0, L_copy_byte);
- }
-
- // Both array are 8 bytes aligned, copy 16 bytes at a time
- __ and3(count, 7, G4); // Save count
- __ srl(count, 3, count);
- generate_disjoint_long_copy_core(aligned);
- __ mov(G4, count); // Restore count
-
- // copy tailing bytes
- __ BIND(L_copy_byte);
- __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit);
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_byte_loop);
- __ ldub(from, offset, O3);
- __ deccc(count);
- __ stb(O3, to, offset);
- __ brx(Assembler::notZero, false, Assembler::pt, L_copy_byte_loop);
- __ delayed()->inc(offset);
- }
-
- __ BIND(L_exit);
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- //
- // Generate stub for conjoint byte copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_conjoint_byte_copy(bool aligned, address nooverlap_target,
- address *entry, const char *name) {
- // Do reverse copy.
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- Label L_skip_alignment, L_align, L_aligned_copy;
- Label L_copy_byte, L_copy_byte_loop, L_exit;
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register end_from = from; // source array end address
- const Register end_to = to; // destination array end address
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
-
- array_overlap_test(nooverlap_target, 0);
-
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, !aligned, false);
-
- __ add(to, count, end_to); // offset after last copied element
-
- // for short arrays, just do single element copy
- __ cmp(count, 23); // 16 + 7
- __ brx(Assembler::less, false, Assembler::pn, L_copy_byte);
- __ delayed()->add(from, count, end_from);
-
- {
- // Align end of arrays since they could be not aligned even
- // when arrays itself are aligned.
-
- // copy bytes to align 'end_to' on 8 byte boundary
- __ andcc(end_to, 7, G1); // misaligned bytes
- __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment);
- __ delayed()->nop();
- __ sub(count, G1, count);
- __ BIND(L_align);
- __ dec(end_from);
- __ dec(end_to);
- __ ldub(end_from, 0, O3);
- __ deccc(G1);
- __ brx(Assembler::notZero, false, Assembler::pt, L_align);
- __ delayed()->stb(O3, end_to, 0);
- __ BIND(L_skip_alignment);
- }
- if (aligned) {
- // Both arrays are aligned to 8-bytes in 64-bits VM.
- // The 'count' is decremented in copy_16_bytes_backward_with_shift()
- // in unaligned case.
- __ dec(count, 16);
- } else {
- // Copy with shift 16 bytes per iteration if arrays do not have
- // the same alignment mod 8, otherwise jump to the next
- // code for aligned copy (and substracting 16 from 'count' before jump).
- // The compare above (count >= 11) guarantes 'count' >= 16 bytes.
- // Also jump over aligned copy after the copy with shift completed.
-
- copy_16_bytes_backward_with_shift(end_from, end_to, count, 16,
- L_aligned_copy, L_copy_byte);
- }
- // copy 4 elements (16 bytes) at a time
- __ align(OptoLoopAlignment);
- __ BIND(L_aligned_copy);
- __ dec(end_from, 16);
- __ ldx(end_from, 8, O3);
- __ ldx(end_from, 0, O4);
- __ dec(end_to, 16);
- __ deccc(count, 16);
- __ stx(O3, end_to, 8);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy);
- __ delayed()->stx(O4, end_to, 0);
- __ inc(count, 16);
-
- // copy 1 element (2 bytes) at a time
- __ BIND(L_copy_byte);
- __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit);
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_byte_loop);
- __ dec(end_from);
- __ dec(end_to);
- __ ldub(end_from, 0, O4);
- __ deccc(count);
- __ brx(Assembler::greater, false, Assembler::pt, L_copy_byte_loop);
- __ delayed()->stb(O4, end_to, 0);
- }
-
- __ BIND(L_exit);
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- //
- // Generate stub for disjoint short copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_disjoint_short_copy(bool aligned, address *entry, const char * name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- Label L_skip_alignment, L_skip_alignment2;
- Label L_copy_2_bytes, L_copy_2_bytes_loop, L_exit;
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register offset = O5; // offset from start of arrays
- // O3, O4, G3, G4 are used as temp registers
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
-
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, !aligned, false);
- // for short arrays, just do single element copy
- __ cmp(count, 11); // 8 + 3 (22 bytes)
- __ brx(Assembler::less, false, Assembler::pn, L_copy_2_bytes);
- __ delayed()->mov(G0, offset);
-
- if (aligned) {
- // 'aligned' == true when it is known statically during compilation
- // of this arraycopy call site that both 'from' and 'to' addresses
- // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()).
- //
- // Aligned arrays have 4 bytes alignment in 32-bits VM
- // and 8 bytes - in 64-bits VM.
- //
- } else {
- // copy 1 element if necessary to align 'to' on an 4 bytes
- __ andcc(to, 3, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment);
- __ delayed()->lduh(from, 0, O3);
- __ inc(from, 2);
- __ inc(to, 2);
- __ dec(count);
- __ sth(O3, to, -2);
- __ BIND(L_skip_alignment);
-
- // copy 2 elements to align 'to' on an 8 byte boundary
- __ andcc(to, 7, G0);
- __ br(Assembler::zero, false, Assembler::pn, L_skip_alignment2);
- __ delayed()->lduh(from, 0, O3);
- __ dec(count, 2);
- __ lduh(from, 2, O4);
- __ inc(from, 4);
- __ inc(to, 4);
- __ sth(O3, to, -4);
- __ sth(O4, to, -2);
- __ BIND(L_skip_alignment2);
- }
- if (!aligned) {
- // Copy with shift 16 bytes per iteration if arrays do not have
- // the same alignment mod 8, otherwise fall through to the next
- // code for aligned copy.
- // The compare above (count >= 11) guarantes 'count' >= 16 bytes.
- // Also jump over aligned copy after the copy with shift completed.
-
- copy_16_bytes_forward_with_shift(from, to, count, 1, L_copy_2_bytes);
- }
-
- // Both array are 8 bytes aligned, copy 16 bytes at a time
- __ and3(count, 3, G4); // Save
- __ srl(count, 2, count);
- generate_disjoint_long_copy_core(aligned);
- __ mov(G4, count); // restore
-
- // copy 1 element at a time
- __ BIND(L_copy_2_bytes);
- __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit);
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_2_bytes_loop);
- __ lduh(from, offset, O3);
- __ deccc(count);
- __ sth(O3, to, offset);
- __ brx(Assembler::notZero, false, Assembler::pt, L_copy_2_bytes_loop);
- __ delayed()->inc(offset, 2);
- }
-
- __ BIND(L_exit);
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jshort_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- //
- // Generate stub for disjoint short fill. If "aligned" is true, the
- // "to" address is assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // to: O0
- // value: O1
- // count: O2 treated as signed
- //
- address generate_fill(BasicType t, bool aligned, const char* name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- const Register to = O0; // source array address
- const Register value = O1; // fill value
- const Register count = O2; // elements count
- // O3 is used as a temp register
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte;
- Label L_fill_2_bytes, L_fill_elements, L_fill_32_bytes;
-
- int shift = -1;
- switch (t) {
- case T_BYTE:
- shift = 2;
- break;
- case T_SHORT:
- shift = 1;
- break;
- case T_INT:
- shift = 0;
- break;
- default: ShouldNotReachHere();
- }
-
- BLOCK_COMMENT("Entry:");
-
- if (t == T_BYTE) {
- // Zero extend value
- __ and3(value, 0xff, value);
- __ sllx(value, 8, O3);
- __ or3(value, O3, value);
- }
- if (t == T_SHORT) {
- // Zero extend value
- __ sllx(value, 48, value);
- __ srlx(value, 48, value);
- }
- if (t == T_BYTE || t == T_SHORT) {
- __ sllx(value, 16, O3);
- __ or3(value, O3, value);
- }
-
- __ cmp(count, 2<andcc(count, 1, G0);
-
- if (!aligned && (t == T_BYTE || t == T_SHORT)) {
- // align source address at 4 bytes address boundary
- if (t == T_BYTE) {
- // One byte misalignment happens only for byte arrays
- __ andcc(to, 1, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_skip_align1);
- __ delayed()->nop();
- __ stb(value, to, 0);
- __ inc(to, 1);
- __ dec(count, 1);
- __ BIND(L_skip_align1);
- }
- // Two bytes misalignment happens only for byte and short (char) arrays
- __ andcc(to, 2, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_skip_align2);
- __ delayed()->nop();
- __ sth(value, to, 0);
- __ inc(to, 2);
- __ dec(count, 1 << (shift - 1));
- __ BIND(L_skip_align2);
- }
- if (!aligned) {
- // align to 8 bytes, we know we are 4 byte aligned to start
- __ andcc(to, 7, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_fill_32_bytes);
- __ delayed()->nop();
- __ stw(value, to, 0);
- __ inc(to, 4);
- __ dec(count, 1 << shift);
- __ BIND(L_fill_32_bytes);
- }
-
- if (t == T_INT) {
- // Zero extend value
- __ srl(value, 0, value);
- }
- if (t == T_BYTE || t == T_SHORT || t == T_INT) {
- __ sllx(value, 32, O3);
- __ or3(value, O3, value);
- }
-
- Label L_check_fill_8_bytes;
- // Fill 32-byte chunks
- __ subcc(count, 8 << shift, count);
- __ brx(Assembler::less, false, Assembler::pt, L_check_fill_8_bytes);
- __ delayed()->nop();
-
- Label L_fill_32_bytes_loop, L_fill_4_bytes;
- __ align(16);
- __ BIND(L_fill_32_bytes_loop);
-
- __ stx(value, to, 0);
- __ stx(value, to, 8);
- __ stx(value, to, 16);
- __ stx(value, to, 24);
-
- __ subcc(count, 8 << shift, count);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_fill_32_bytes_loop);
- __ delayed()->add(to, 32, to);
-
- __ BIND(L_check_fill_8_bytes);
- __ addcc(count, 8 << shift, count);
- __ brx(Assembler::zero, false, Assembler::pn, L_exit);
- __ delayed()->subcc(count, 1 << (shift + 1), count);
- __ brx(Assembler::less, false, Assembler::pn, L_fill_4_bytes);
- __ delayed()->andcc(count, 1<add(to, 8, to);
-
- // fill trailing 4 bytes
- __ andcc(count, 1<andcc(count, 1<<(shift-1), G0);
- } else {
- __ delayed()->nop();
- }
- __ stw(value, to, 0);
- if (t == T_BYTE || t == T_SHORT) {
- __ inc(to, 4);
- // fill trailing 2 bytes
- __ andcc(count, 1<<(shift-1), G0); // in delay slot of branches
- __ BIND(L_fill_2_bytes);
- __ brx(Assembler::zero, false, Assembler::pt, L_fill_byte);
- __ delayed()->andcc(count, 1, count);
- __ sth(value, to, 0);
- if (t == T_BYTE) {
- __ inc(to, 2);
- // fill trailing byte
- __ andcc(count, 1, count); // in delay slot of branches
- __ BIND(L_fill_byte);
- __ brx(Assembler::zero, false, Assembler::pt, L_exit);
- __ delayed()->nop();
- __ stb(value, to, 0);
- } else {
- __ BIND(L_fill_byte);
- }
- } else {
- __ BIND(L_fill_2_bytes);
- }
- __ BIND(L_exit);
- __ retl();
- __ delayed()->nop();
-
- // Handle copies less than 8 bytes. Int is handled elsewhere.
- if (t == T_BYTE) {
- __ BIND(L_fill_elements);
- Label L_fill_2, L_fill_4;
- // in delay slot __ andcc(count, 1, G0);
- __ brx(Assembler::zero, false, Assembler::pt, L_fill_2);
- __ delayed()->andcc(count, 2, G0);
- __ stb(value, to, 0);
- __ inc(to, 1);
- __ BIND(L_fill_2);
- __ brx(Assembler::zero, false, Assembler::pt, L_fill_4);
- __ delayed()->andcc(count, 4, G0);
- __ stb(value, to, 0);
- __ stb(value, to, 1);
- __ inc(to, 2);
- __ BIND(L_fill_4);
- __ brx(Assembler::zero, false, Assembler::pt, L_exit);
- __ delayed()->nop();
- __ stb(value, to, 0);
- __ stb(value, to, 1);
- __ stb(value, to, 2);
- __ retl();
- __ delayed()->stb(value, to, 3);
- }
-
- if (t == T_SHORT) {
- Label L_fill_2;
- __ BIND(L_fill_elements);
- // in delay slot __ andcc(count, 1, G0);
- __ brx(Assembler::zero, false, Assembler::pt, L_fill_2);
- __ delayed()->andcc(count, 2, G0);
- __ sth(value, to, 0);
- __ inc(to, 2);
- __ BIND(L_fill_2);
- __ brx(Assembler::zero, false, Assembler::pt, L_exit);
- __ delayed()->nop();
- __ sth(value, to, 0);
- __ retl();
- __ delayed()->sth(value, to, 2);
- }
- return start;
- }
-
- //
- // Generate stub for conjoint short copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_conjoint_short_copy(bool aligned, address nooverlap_target,
- address *entry, const char *name) {
- // Do reverse copy.
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- Label L_skip_alignment, L_skip_alignment2, L_aligned_copy;
- Label L_copy_2_bytes, L_copy_2_bytes_loop, L_exit;
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register end_from = from; // source array end address
- const Register end_to = to; // destination array end address
-
- const Register byte_count = O3; // bytes count to copy
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
-
- array_overlap_test(nooverlap_target, 1);
-
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, !aligned, false);
-
- __ sllx(count, LogBytesPerShort, byte_count);
- __ add(to, byte_count, end_to); // offset after last copied element
-
- // for short arrays, just do single element copy
- __ cmp(count, 11); // 8 + 3 (22 bytes)
- __ brx(Assembler::less, false, Assembler::pn, L_copy_2_bytes);
- __ delayed()->add(from, byte_count, end_from);
-
- {
- // Align end of arrays since they could be not aligned even
- // when arrays itself are aligned.
-
- // copy 1 element if necessary to align 'end_to' on an 4 bytes
- __ andcc(end_to, 3, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment);
- __ delayed()->lduh(end_from, -2, O3);
- __ dec(end_from, 2);
- __ dec(end_to, 2);
- __ dec(count);
- __ sth(O3, end_to, 0);
- __ BIND(L_skip_alignment);
-
- // copy 2 elements to align 'end_to' on an 8 byte boundary
- __ andcc(end_to, 7, G0);
- __ br(Assembler::zero, false, Assembler::pn, L_skip_alignment2);
- __ delayed()->lduh(end_from, -2, O3);
- __ dec(count, 2);
- __ lduh(end_from, -4, O4);
- __ dec(end_from, 4);
- __ dec(end_to, 4);
- __ sth(O3, end_to, 2);
- __ sth(O4, end_to, 0);
- __ BIND(L_skip_alignment2);
- }
- if (aligned) {
- // Both arrays are aligned to 8-bytes in 64-bits VM.
- // The 'count' is decremented in copy_16_bytes_backward_with_shift()
- // in unaligned case.
- __ dec(count, 8);
- } else {
- // Copy with shift 16 bytes per iteration if arrays do not have
- // the same alignment mod 8, otherwise jump to the next
- // code for aligned copy (and substracting 8 from 'count' before jump).
- // The compare above (count >= 11) guarantes 'count' >= 16 bytes.
- // Also jump over aligned copy after the copy with shift completed.
-
- copy_16_bytes_backward_with_shift(end_from, end_to, count, 8,
- L_aligned_copy, L_copy_2_bytes);
- }
- // copy 4 elements (16 bytes) at a time
- __ align(OptoLoopAlignment);
- __ BIND(L_aligned_copy);
- __ dec(end_from, 16);
- __ ldx(end_from, 8, O3);
- __ ldx(end_from, 0, O4);
- __ dec(end_to, 16);
- __ deccc(count, 8);
- __ stx(O3, end_to, 8);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy);
- __ delayed()->stx(O4, end_to, 0);
- __ inc(count, 8);
-
- // copy 1 element (2 bytes) at a time
- __ BIND(L_copy_2_bytes);
- __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit);
- __ BIND(L_copy_2_bytes_loop);
- __ dec(end_from, 2);
- __ dec(end_to, 2);
- __ lduh(end_from, 0, O4);
- __ deccc(count);
- __ brx(Assembler::greater, false, Assembler::pt, L_copy_2_bytes_loop);
- __ delayed()->sth(O4, end_to, 0);
- }
- __ BIND(L_exit);
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jshort_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- //
- // Helper methods for generate_disjoint_int_copy_core()
- //
- void copy_16_bytes_loop(Register from, Register to, Register count, int count_dec,
- Label& L_loop, bool use_prefetch, bool use_bis) {
-
- __ align(OptoLoopAlignment);
- __ BIND(L_loop);
- if (use_prefetch) {
- if (ArraycopySrcPrefetchDistance > 0) {
- __ prefetch(from, ArraycopySrcPrefetchDistance, Assembler::severalReads);
- }
- if (ArraycopyDstPrefetchDistance > 0) {
- __ prefetch(to, ArraycopyDstPrefetchDistance, Assembler::severalWritesAndPossiblyReads);
- }
- }
- __ ldx(from, 4, O4);
- __ ldx(from, 12, G4);
- __ inc(to, 16);
- __ inc(from, 16);
- __ deccc(count, 4); // Can we do next iteration after this one?
-
- __ srlx(O4, 32, G3);
- __ bset(G3, O3);
- __ sllx(O4, 32, O4);
- __ srlx(G4, 32, G3);
- __ bset(G3, O4);
- if (use_bis) {
- __ stxa(O3, to, -16);
- __ stxa(O4, to, -8);
- } else {
- __ stx(O3, to, -16);
- __ stx(O4, to, -8);
- }
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
- __ delayed()->sllx(G4, 32, O3);
-
- }
-
- //
- // Generate core code for disjoint int copy (and oop copy on 32-bit).
- // If "aligned" is true, the "from" and "to" addresses are assumed
- // to be heapword aligned.
- //
- // Arguments:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- void generate_disjoint_int_copy_core(bool aligned) {
-
- Label L_skip_alignment, L_aligned_copy;
- Label L_copy_4_bytes, L_copy_4_bytes_loop, L_exit;
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register offset = O5; // offset from start of arrays
- // O3, O4, G3, G4 are used as temp registers
-
- // 'aligned' == true when it is known statically during compilation
- // of this arraycopy call site that both 'from' and 'to' addresses
- // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()).
- //
- // Aligned arrays have 4 bytes alignment in 32-bits VM
- // and 8 bytes - in 64-bits VM.
- //
- if (!aligned) {
- // The next check could be put under 'ifndef' since the code in
- // generate_disjoint_long_copy_core() has own checks and set 'offset'.
-
- // for short arrays, just do single element copy
- __ cmp(count, 5); // 4 + 1 (20 bytes)
- __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_4_bytes);
- __ delayed()->mov(G0, offset);
-
- // copy 1 element to align 'to' on an 8 byte boundary
- __ andcc(to, 7, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment);
- __ delayed()->ld(from, 0, O3);
- __ inc(from, 4);
- __ inc(to, 4);
- __ dec(count);
- __ st(O3, to, -4);
- __ BIND(L_skip_alignment);
-
- // if arrays have same alignment mod 8, do 4 elements copy
- __ andcc(from, 7, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy);
- __ delayed()->ld(from, 0, O3);
-
- //
- // Load 2 aligned 8-bytes chunks and use one from previous iteration
- // to form 2 aligned 8-bytes chunks to store.
- //
- // copy_16_bytes_forward_with_shift() is not used here since this
- // code is more optimal.
-
- // copy with shift 4 elements (16 bytes) at a time
- __ dec(count, 4); // The cmp at the beginning guaranty count >= 4
- __ sllx(O3, 32, O3);
-
- disjoint_copy_core(from, to, count, 2, 16, &StubGenerator::copy_16_bytes_loop);
-
- __ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes);
- __ delayed()->inc(count, 4); // restore 'count'
-
- __ BIND(L_aligned_copy);
- } // !aligned
-
- // copy 4 elements (16 bytes) at a time
- __ and3(count, 1, G4); // Save
- __ srl(count, 1, count);
- generate_disjoint_long_copy_core(aligned);
- __ mov(G4, count); // Restore
-
- // copy 1 element at a time
- __ BIND(L_copy_4_bytes);
- __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit);
- __ BIND(L_copy_4_bytes_loop);
- __ ld(from, offset, O3);
- __ deccc(count);
- __ st(O3, to, offset);
- __ brx(Assembler::notZero, false, Assembler::pt, L_copy_4_bytes_loop);
- __ delayed()->inc(offset, 4);
- __ BIND(L_exit);
- }
-
- //
- // Generate stub for disjoint int copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_disjoint_int_copy(bool aligned, address *entry, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- const Register count = O2;
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, !aligned, false);
- generate_disjoint_int_copy_core(aligned);
- }
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jint_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- //
- // Generate core code for conjoint int copy (and oop copy on 32-bit).
- // If "aligned" is true, the "from" and "to" addresses are assumed
- // to be heapword aligned.
- //
- // Arguments:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- void generate_conjoint_int_copy_core(bool aligned) {
- // Do reverse copy.
-
- Label L_skip_alignment, L_aligned_copy;
- Label L_copy_16_bytes, L_copy_4_bytes, L_copy_4_bytes_loop, L_exit;
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register end_from = from; // source array end address
- const Register end_to = to; // destination array end address
- // O3, O4, O5, G3 are used as temp registers
-
- const Register byte_count = O3; // bytes count to copy
-
- __ sllx(count, LogBytesPerInt, byte_count);
- __ add(to, byte_count, end_to); // offset after last copied element
-
- __ cmp(count, 5); // for short arrays, just do single element copy
- __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_4_bytes);
- __ delayed()->add(from, byte_count, end_from);
-
- // copy 1 element to align 'to' on an 8 byte boundary
- __ andcc(end_to, 7, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment);
- __ delayed()->nop();
- __ dec(count);
- __ dec(end_from, 4);
- __ dec(end_to, 4);
- __ ld(end_from, 0, O4);
- __ st(O4, end_to, 0);
- __ BIND(L_skip_alignment);
-
- // Check if 'end_from' and 'end_to' has the same alignment.
- __ andcc(end_from, 7, G0);
- __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy);
- __ delayed()->dec(count, 4); // The cmp at the start guaranty cnt >= 4
-
- // copy with shift 4 elements (16 bytes) at a time
- //
- // Load 2 aligned 8-bytes chunks and use one from previous iteration
- // to form 2 aligned 8-bytes chunks to store.
- //
- __ ldx(end_from, -4, O3);
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_16_bytes);
- __ ldx(end_from, -12, O4);
- __ deccc(count, 4);
- __ ldx(end_from, -20, O5);
- __ dec(end_to, 16);
- __ dec(end_from, 16);
- __ srlx(O3, 32, O3);
- __ sllx(O4, 32, G3);
- __ bset(G3, O3);
- __ stx(O3, end_to, 8);
- __ srlx(O4, 32, O4);
- __ sllx(O5, 32, G3);
- __ bset(O4, G3);
- __ stx(G3, end_to, 0);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes);
- __ delayed()->mov(O5, O3);
-
- __ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes);
- __ delayed()->inc(count, 4);
-
- // copy 4 elements (16 bytes) at a time
- __ align(OptoLoopAlignment);
- __ BIND(L_aligned_copy);
- __ dec(end_from, 16);
- __ ldx(end_from, 8, O3);
- __ ldx(end_from, 0, O4);
- __ dec(end_to, 16);
- __ deccc(count, 4);
- __ stx(O3, end_to, 8);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy);
- __ delayed()->stx(O4, end_to, 0);
- __ inc(count, 4);
-
- // copy 1 element (4 bytes) at a time
- __ BIND(L_copy_4_bytes);
- __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit);
- __ BIND(L_copy_4_bytes_loop);
- __ dec(end_from, 4);
- __ dec(end_to, 4);
- __ ld(end_from, 0, O4);
- __ deccc(count);
- __ brx(Assembler::greater, false, Assembler::pt, L_copy_4_bytes_loop);
- __ delayed()->st(O4, end_to, 0);
- __ BIND(L_exit);
- }
-
- //
- // Generate stub for conjoint int copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_conjoint_int_copy(bool aligned, address nooverlap_target,
- address *entry, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- assert_clean_int(O2, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
-
- array_overlap_test(nooverlap_target, 2);
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, !aligned, false);
- generate_conjoint_int_copy_core(aligned);
- }
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jint_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- //
- // Helper methods for generate_disjoint_long_copy_core()
- //
- void copy_64_bytes_loop(Register from, Register to, Register count, int count_dec,
- Label& L_loop, bool use_prefetch, bool use_bis) {
- __ align(OptoLoopAlignment);
- __ BIND(L_loop);
- for (int off = 0; off < 64; off += 16) {
- if (use_prefetch && (off & 31) == 0) {
- if (ArraycopySrcPrefetchDistance > 0) {
- __ prefetch(from, ArraycopySrcPrefetchDistance+off, Assembler::severalReads);
- }
- if (ArraycopyDstPrefetchDistance > 0) {
- __ prefetch(to, ArraycopyDstPrefetchDistance+off, Assembler::severalWritesAndPossiblyReads);
- }
- }
- __ ldx(from, off+0, O4);
- __ ldx(from, off+8, O5);
- if (use_bis) {
- __ stxa(O4, to, off+0);
- __ stxa(O5, to, off+8);
- } else {
- __ stx(O4, to, off+0);
- __ stx(O5, to, off+8);
- }
- }
- __ deccc(count, 8);
- __ inc(from, 64);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
- __ delayed()->inc(to, 64);
- }
-
- //
- // Generate core code for disjoint long copy (and oop copy on 64-bit).
- // "aligned" is ignored, because we must make the stronger
- // assumption that both addresses are always 64-bit aligned.
- //
- // Arguments:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- // count -= 2;
- // if ( count >= 0 ) { // >= 2 elements
- // if ( count > 6) { // >= 8 elements
- // count -= 6; // original count - 8
- // do {
- // copy_8_elements;
- // count -= 8;
- // } while ( count >= 0 );
- // count += 6;
- // }
- // if ( count >= 0 ) { // >= 2 elements
- // do {
- // copy_2_elements;
- // } while ( (count=count-2) >= 0 );
- // }
- // }
- // count += 2;
- // if ( count != 0 ) { // 1 element left
- // copy_1_element;
- // }
- //
- void generate_disjoint_long_copy_core(bool aligned) {
- Label L_copy_8_bytes, L_copy_16_bytes, L_exit;
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register offset0 = O4; // element offset
- const Register offset8 = O5; // next element offset
-
- __ deccc(count, 2);
- __ mov(G0, offset0); // offset from start of arrays (0)
- __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes );
- __ delayed()->add(offset0, 8, offset8);
-
- // Copy by 64 bytes chunks
-
- const Register from64 = O3; // source address
- const Register to64 = G3; // destination address
- __ subcc(count, 6, O3);
- __ brx(Assembler::negative, false, Assembler::pt, L_copy_16_bytes );
- __ delayed()->mov(to, to64);
- // Now we can use O4(offset0), O5(offset8) as temps
- __ mov(O3, count);
- // count >= 0 (original count - 8)
- __ mov(from, from64);
-
- disjoint_copy_core(from64, to64, count, 3, 64, &StubGenerator::copy_64_bytes_loop);
-
- // Restore O4(offset0), O5(offset8)
- __ sub(from64, from, offset0);
- __ inccc(count, 6); // restore count
- __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes );
- __ delayed()->add(offset0, 8, offset8);
-
- // Copy by 16 bytes chunks
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_16_bytes);
- __ ldx(from, offset0, O3);
- __ ldx(from, offset8, G3);
- __ deccc(count, 2);
- __ stx(O3, to, offset0);
- __ inc(offset0, 16);
- __ stx(G3, to, offset8);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes);
- __ delayed()->inc(offset8, 16);
-
- // Copy last 8 bytes
- __ BIND(L_copy_8_bytes);
- __ inccc(count, 2);
- __ brx(Assembler::zero, true, Assembler::pn, L_exit );
- __ delayed()->mov(offset0, offset8); // Set O5 used by other stubs
- __ ldx(from, offset0, O3);
- __ stx(O3, to, offset0);
- __ BIND(L_exit);
- }
-
- //
- // Generate stub for disjoint long copy.
- // "aligned" is ignored, because we must make the stronger
- // assumption that both addresses are always 64-bit aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_disjoint_long_copy(bool aligned, address *entry, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- assert_clean_int(O2, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
-
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, true, false);
- generate_disjoint_long_copy_core(aligned);
- }
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jlong_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- //
- // Generate core code for conjoint long copy (and oop copy on 64-bit).
- // "aligned" is ignored, because we must make the stronger
- // assumption that both addresses are always 64-bit aligned.
- //
- // Arguments:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- void generate_conjoint_long_copy_core(bool aligned) {
- // Do reverse copy.
- Label L_copy_8_bytes, L_copy_16_bytes, L_exit;
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
- const Register offset8 = O4; // element offset
- const Register offset0 = O5; // previous element offset
-
- __ subcc(count, 1, count);
- __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_8_bytes );
- __ delayed()->sllx(count, LogBytesPerLong, offset8);
- __ sub(offset8, 8, offset0);
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_16_bytes);
- __ ldx(from, offset8, O2);
- __ ldx(from, offset0, O3);
- __ stx(O2, to, offset8);
- __ deccc(offset8, 16); // use offset8 as counter
- __ stx(O3, to, offset0);
- __ brx(Assembler::greater, false, Assembler::pt, L_copy_16_bytes);
- __ delayed()->dec(offset0, 16);
-
- __ BIND(L_copy_8_bytes);
- __ brx(Assembler::negative, false, Assembler::pn, L_exit );
- __ delayed()->nop();
- __ ldx(from, 0, O3);
- __ stx(O3, to, 0);
- __ BIND(L_exit);
- }
-
- // Generate stub for conjoint long copy.
- // "aligned" is ignored, because we must make the stronger
- // assumption that both addresses are always 64-bit aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_conjoint_long_copy(bool aligned, address nooverlap_target,
- address *entry, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- assert(aligned, "Should always be aligned");
-
- assert_clean_int(O2, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
- BLOCK_COMMENT("Entry:");
- }
-
- array_overlap_test(nooverlap_target, 3);
- {
- // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit
- UnsafeCopyMemoryMark ucmm(this, true, false);
- generate_conjoint_long_copy_core(aligned);
- }
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_jlong_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- // Generate stub for disjoint oop copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_disjoint_oop_copy(bool aligned, address *entry, const char *name,
- bool dest_uninitialized = false) {
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here
- BLOCK_COMMENT("Entry:");
- }
-
- DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT;
- if (dest_uninitialized) {
- decorators |= IS_DEST_UNINITIALIZED;
- }
- if (aligned) {
- decorators |= ARRAYCOPY_ALIGNED;
- }
-
- BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->arraycopy_prologue(_masm, decorators, T_OBJECT, from, to, count);
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
- if (UseCompressedOops) {
- generate_disjoint_int_copy_core(aligned);
- } else {
- generate_disjoint_long_copy_core(aligned);
- }
-
- bs->arraycopy_epilogue(_masm, decorators, T_OBJECT, from, to, count);
-
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_oop_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
- // Generate stub for conjoint oop copy. If "aligned" is true, the
- // "from" and "to" addresses are assumed to be heapword aligned.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- //
- address generate_conjoint_oop_copy(bool aligned, address nooverlap_target,
- address *entry, const char *name,
- bool dest_uninitialized = false) {
-
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- assert_clean_int(count, O3); // Make sure 'count' is clean int.
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here
- BLOCK_COMMENT("Entry:");
- }
-
- array_overlap_test(nooverlap_target, LogBytesPerHeapOop);
-
- DecoratorSet decorators = IN_HEAP | IS_ARRAY;
- if (dest_uninitialized) {
- decorators |= IS_DEST_UNINITIALIZED;
- }
- if (aligned) {
- decorators |= ARRAYCOPY_ALIGNED;
- }
-
- BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->arraycopy_prologue(_masm, decorators, T_OBJECT, from, to, count);
-
- if (UseCompressedOops) {
- generate_conjoint_int_copy_core(aligned);
- } else {
- generate_conjoint_long_copy_core(aligned);
- }
-
- bs->arraycopy_epilogue(_masm, decorators, T_OBJECT, from, to, count);
-
- // O3, O4 are used as temp registers
- inc_counter_np(SharedRuntime::_oop_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->mov(G0, O0); // return 0
- return start;
- }
-
-
- // Helper for generating a dynamic type check.
- // Smashes only the given temp registers.
- void generate_type_check(Register sub_klass,
- Register super_check_offset,
- Register super_klass,
- Register temp,
- Label& L_success) {
- assert_different_registers(sub_klass, super_check_offset, super_klass, temp);
-
- BLOCK_COMMENT("type_check:");
-
- Label L_miss, L_pop_to_miss;
-
- assert_clean_int(super_check_offset, temp);
-
- __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, noreg,
- &L_success, &L_miss, NULL,
- super_check_offset);
-
- BLOCK_COMMENT("type_check_slow_path:");
- __ save_frame(0);
- __ check_klass_subtype_slow_path(sub_klass->after_save(),
- super_klass->after_save(),
- L0, L1, L2, L4,
- NULL, &L_pop_to_miss);
- __ ba(L_success);
- __ delayed()->restore();
-
- __ bind(L_pop_to_miss);
- __ restore();
-
- // Fall through on failure!
- __ BIND(L_miss);
- }
-
-
- // Generate stub for checked oop copy.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 treated as signed
- // ckoff: O3 (super_check_offset)
- // ckval: O4 (super_klass)
- // ret: O0 zero for success; (-1^K) where K is partial transfer count
- //
- address generate_checkcast_copy(const char *name, address *entry, bool dest_uninitialized = false) {
-
- const Register O0_from = O0; // source array address
- const Register O1_to = O1; // destination array address
- const Register O2_count = O2; // elements count
- const Register O3_ckoff = O3; // super_check_offset
- const Register O4_ckval = O4; // super_klass
-
- const Register O5_offset = O5; // loop var, with stride wordSize
- const Register G1_remain = G1; // loop var, with stride -1
- const Register G3_oop = G3; // actual oop copied
- const Register G4_klass = G4; // oop._klass
- const Register G5_super = G5; // oop._klass._primary_supers[ckval]
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
-#ifdef ASSERT
- // We sometimes save a frame (see generate_type_check below).
- // If this will cause trouble, let's fail now instead of later.
- __ save_frame(0);
- __ restore();
-#endif
-
- assert_clean_int(O2_count, G1); // Make sure 'count' is clean int.
-
-#ifdef ASSERT
- // caller guarantees that the arrays really are different
- // otherwise, we would have to make conjoint checks
- { Label L;
- __ mov(O3, G1); // spill: overlap test smashes O3
- __ mov(O4, G4); // spill: overlap test smashes O4
- array_overlap_test(L, LogBytesPerHeapOop);
- __ stop("checkcast_copy within a single array");
- __ bind(L);
- __ mov(G1, O3);
- __ mov(G4, O4);
- }
-#endif //ASSERT
-
- if (entry != NULL) {
- *entry = __ pc();
- // caller can pass a 64-bit byte count here (from generic stub)
- BLOCK_COMMENT("Entry:");
- }
-
- DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST;
- if (dest_uninitialized) {
- decorators |= IS_DEST_UNINITIALIZED;
- }
-
- BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->arraycopy_prologue(_masm, decorators, T_OBJECT, O0_from, O1_to, O2_count);
-
- Label load_element, store_element, do_epilogue, fail, done;
- __ addcc(O2_count, 0, G1_remain); // initialize loop index, and test it
- __ brx(Assembler::notZero, false, Assembler::pt, load_element);
- __ delayed()->mov(G0, O5_offset); // offset from start of arrays
-
- // Empty array: Nothing to do.
- inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->set(0, O0); // return 0 on (trivial) success
-
- // ======== begin loop ========
- // (Loop is rotated; its entry is load_element.)
- // Loop variables:
- // (O5 = 0; ; O5 += wordSize) --- offset from src, dest arrays
- // (O2 = len; O2 != 0; O2--) --- number of oops *remaining*
- // G3, G4, G5 --- current oop, oop.klass, oop.klass.super
- __ align(OptoLoopAlignment);
-
- __ BIND(store_element);
- __ deccc(G1_remain); // decrement the count
- __ store_heap_oop(G3_oop, O1_to, O5_offset, noreg, AS_RAW); // store the oop
- __ inc(O5_offset, heapOopSize); // step to next offset
- __ brx(Assembler::zero, true, Assembler::pt, do_epilogue);
- __ delayed()->set(0, O0); // return -1 on success
-
- // ======== loop entry is here ========
- __ BIND(load_element);
- __ load_heap_oop(O0_from, O5_offset, G3_oop, noreg, AS_RAW); // load the oop
- __ br_null_short(G3_oop, Assembler::pt, store_element);
-
- __ load_klass(G3_oop, G4_klass); // query the object klass
-
- generate_type_check(G4_klass, O3_ckoff, O4_ckval, G5_super,
- // branch to this on success:
- store_element);
- // ======== end loop ========
-
- // It was a real error; we must depend on the caller to finish the job.
- // Register G1 has number of *remaining* oops, O2 number of *total* oops.
- // Emit GC store barriers for the oops we have copied (O2 minus G1),
- // and report their number to the caller.
- __ BIND(fail);
- __ subcc(O2_count, G1_remain, O2_count);
- __ brx(Assembler::zero, false, Assembler::pt, done);
- __ delayed()->not1(O2_count, O0); // report (-1^K) to caller
-
- __ BIND(do_epilogue);
- bs->arraycopy_epilogue(_masm, decorators, T_OBJECT, O0_from, O1_to, O2_count);
-
- __ BIND(done);
- inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4);
- __ retl();
- __ delayed()->nop(); // return value in 00
-
- return start;
- }
-
-
- // Generate 'unsafe' array copy stub
- // Though just as safe as the other stubs, it takes an unscaled
- // size_t argument instead of an element count.
- //
- // Arguments for generated stub:
- // from: O0
- // to: O1
- // count: O2 byte count, treated as ssize_t, can be zero
- //
- // Examines the alignment of the operands and dispatches
- // to a long, int, short, or byte copy loop.
- //
- address generate_unsafe_copy(const char* name,
- address byte_copy_entry,
- address short_copy_entry,
- address int_copy_entry,
- address long_copy_entry) {
-
- const Register O0_from = O0; // source array address
- const Register O1_to = O1; // destination array address
- const Register O2_count = O2; // elements count
-
- const Register G1_bits = G1; // test copy of low bits
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- // bump this on entry, not on exit:
- inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr, G1, G3);
-
- __ or3(O0_from, O1_to, G1_bits);
- __ or3(O2_count, G1_bits, G1_bits);
-
- __ btst(BytesPerLong-1, G1_bits);
- __ br(Assembler::zero, true, Assembler::pt,
- long_copy_entry, relocInfo::runtime_call_type);
- // scale the count on the way out:
- __ delayed()->srax(O2_count, LogBytesPerLong, O2_count);
-
- __ btst(BytesPerInt-1, G1_bits);
- __ br(Assembler::zero, true, Assembler::pt,
- int_copy_entry, relocInfo::runtime_call_type);
- // scale the count on the way out:
- __ delayed()->srax(O2_count, LogBytesPerInt, O2_count);
-
- __ btst(BytesPerShort-1, G1_bits);
- __ br(Assembler::zero, true, Assembler::pt,
- short_copy_entry, relocInfo::runtime_call_type);
- // scale the count on the way out:
- __ delayed()->srax(O2_count, LogBytesPerShort, O2_count);
-
- __ br(Assembler::always, false, Assembler::pt,
- byte_copy_entry, relocInfo::runtime_call_type);
- __ delayed()->nop();
-
- return start;
- }
-
-
- // Perform range checks on the proposed arraycopy.
- // Kills the two temps, but nothing else.
- // Also, clean the sign bits of src_pos and dst_pos.
- void arraycopy_range_checks(Register src, // source array oop (O0)
- Register src_pos, // source position (O1)
- Register dst, // destination array oo (O2)
- Register dst_pos, // destination position (O3)
- Register length, // length of copy (O4)
- Register temp1, Register temp2,
- Label& L_failed) {
- BLOCK_COMMENT("arraycopy_range_checks:");
-
- // if (src_pos + length > arrayOop(src)->length() ) FAIL;
-
- const Register array_length = temp1; // scratch
- const Register end_pos = temp2; // scratch
-
- // Note: This next instruction may be in the delay slot of a branch:
- __ add(length, src_pos, end_pos); // src_pos + length
- __ lduw(src, arrayOopDesc::length_offset_in_bytes(), array_length);
- __ cmp(end_pos, array_length);
- __ br(Assembler::greater, false, Assembler::pn, L_failed);
-
- // if (dst_pos + length > arrayOop(dst)->length() ) FAIL;
- __ delayed()->add(length, dst_pos, end_pos); // dst_pos + length
- __ lduw(dst, arrayOopDesc::length_offset_in_bytes(), array_length);
- __ cmp(end_pos, array_length);
- __ br(Assembler::greater, false, Assembler::pn, L_failed);
-
- // Have to clean up high 32-bits of 'src_pos' and 'dst_pos'.
- // Move with sign extension can be used since they are positive.
- __ delayed()->signx(src_pos, src_pos);
- __ signx(dst_pos, dst_pos);
-
- BLOCK_COMMENT("arraycopy_range_checks done");
- }
-
-
- //
- // Generate generic array copy stubs
- //
- // Input:
- // O0 - src oop
- // O1 - src_pos
- // O2 - dst oop
- // O3 - dst_pos
- // O4 - element count
- //
- // Output:
- // O0 == 0 - success
- // O0 == -1 - need to call System.arraycopy
- //
- address generate_generic_copy(const char *name,
- address entry_jbyte_arraycopy,
- address entry_jshort_arraycopy,
- address entry_jint_arraycopy,
- address entry_oop_arraycopy,
- address entry_jlong_arraycopy,
- address entry_checkcast_arraycopy) {
- Label L_failed, L_objArray;
-
- // Input registers
- const Register src = O0; // source array oop
- const Register src_pos = O1; // source position
- const Register dst = O2; // destination array oop
- const Register dst_pos = O3; // destination position
- const Register length = O4; // elements count
-
- // registers used as temp
- const Register G3_src_klass = G3; // source array klass
- const Register G4_dst_klass = G4; // destination array klass
- const Register G5_lh = G5; // layout handler
- const Register O5_temp = O5;
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- // bump this on entry, not on exit:
- inc_counter_np(SharedRuntime::_generic_array_copy_ctr, G1, G3);
-
- // In principle, the int arguments could be dirty.
- //assert_clean_int(src_pos, G1);
- //assert_clean_int(dst_pos, G1);
- //assert_clean_int(length, G1);
-
- //-----------------------------------------------------------------------
- // Assembler stubs will be used for this call to arraycopy
- // if the following conditions are met:
- //
- // (1) src and dst must not be null.
- // (2) src_pos must not be negative.
- // (3) dst_pos must not be negative.
- // (4) length must not be negative.
- // (5) src klass and dst klass should be the same and not NULL.
- // (6) src and dst should be arrays.
- // (7) src_pos + length must not exceed length of src.
- // (8) dst_pos + length must not exceed length of dst.
- BLOCK_COMMENT("arraycopy initial argument checks");
-
- // if (src == NULL) return -1;
- __ br_null(src, false, Assembler::pn, L_failed);
-
- // if (src_pos < 0) return -1;
- __ delayed()->tst(src_pos);
- __ br(Assembler::negative, false, Assembler::pn, L_failed);
- __ delayed()->nop();
-
- // if (dst == NULL) return -1;
- __ br_null(dst, false, Assembler::pn, L_failed);
-
- // if (dst_pos < 0) return -1;
- __ delayed()->tst(dst_pos);
- __ br(Assembler::negative, false, Assembler::pn, L_failed);
-
- // if (length < 0) return -1;
- __ delayed()->tst(length);
- __ br(Assembler::negative, false, Assembler::pn, L_failed);
-
- BLOCK_COMMENT("arraycopy argument klass checks");
- // get src->klass()
- if (UseCompressedClassPointers) {
- __ delayed()->nop(); // ??? not good
- __ load_klass(src, G3_src_klass);
- } else {
- __ delayed()->ld_ptr(src, oopDesc::klass_offset_in_bytes(), G3_src_klass);
- }
-
-#ifdef ASSERT
- // assert(src->klass() != NULL);
- BLOCK_COMMENT("assert klasses not null");
- { Label L_a, L_b;
- __ br_notnull_short(G3_src_klass, Assembler::pt, L_b); // it is broken if klass is NULL
- __ bind(L_a);
- __ stop("broken null klass");
- __ bind(L_b);
- __ load_klass(dst, G4_dst_klass);
- __ br_null(G4_dst_klass, false, Assembler::pn, L_a); // this would be broken also
- __ delayed()->mov(G0, G4_dst_klass); // scribble the temp
- BLOCK_COMMENT("assert done");
- }
-#endif
-
- // Load layout helper
- //
- // |array_tag| | header_size | element_type | |log2_element_size|
- // 32 30 24 16 8 2 0
- //
- // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0
- //
-
- int lh_offset = in_bytes(Klass::layout_helper_offset());
-
- // Load 32-bits signed value. Use br() instruction with it to check icc.
- __ lduw(G3_src_klass, lh_offset, G5_lh);
-
- if (UseCompressedClassPointers) {
- __ load_klass(dst, G4_dst_klass);
- }
- // Handle objArrays completely differently...
- juint objArray_lh = Klass::array_layout_helper(T_OBJECT);
- __ set(objArray_lh, O5_temp);
- __ cmp(G5_lh, O5_temp);
- __ br(Assembler::equal, false, Assembler::pt, L_objArray);
- if (UseCompressedClassPointers) {
- __ delayed()->nop();
- } else {
- __ delayed()->ld_ptr(dst, oopDesc::klass_offset_in_bytes(), G4_dst_klass);
- }
-
- // if (src->klass() != dst->klass()) return -1;
- __ cmp_and_brx_short(G3_src_klass, G4_dst_klass, Assembler::notEqual, Assembler::pn, L_failed);
-
- // if (!src->is_Array()) return -1;
- __ cmp(G5_lh, Klass::_lh_neutral_value); // < 0
- __ br(Assembler::greaterEqual, false, Assembler::pn, L_failed);
-
- // At this point, it is known to be a typeArray (array_tag 0x3).
-#ifdef ASSERT
- __ delayed()->nop();
- { Label L;
- jint lh_prim_tag_in_place = (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift);
- __ set(lh_prim_tag_in_place, O5_temp);
- __ cmp(G5_lh, O5_temp);
- __ br(Assembler::greaterEqual, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("must be a primitive array");
- __ bind(L);
- }
-#else
- __ delayed(); // match next insn to prev branch
-#endif
-
- arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
- O5_temp, G4_dst_klass, L_failed);
-
- // TypeArrayKlass
- //
- // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize);
- // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize);
- //
-
- const Register G4_offset = G4_dst_klass; // array offset
- const Register G3_elsize = G3_src_klass; // log2 element size
-
- __ srl(G5_lh, Klass::_lh_header_size_shift, G4_offset);
- __ and3(G4_offset, Klass::_lh_header_size_mask, G4_offset); // array_offset
- __ add(src, G4_offset, src); // src array offset
- __ add(dst, G4_offset, dst); // dst array offset
- __ and3(G5_lh, Klass::_lh_log2_element_size_mask, G3_elsize); // log2 element size
-
- // next registers should be set before the jump to corresponding stub
- const Register from = O0; // source array address
- const Register to = O1; // destination array address
- const Register count = O2; // elements count
-
- // 'from', 'to', 'count' registers should be set in this order
- // since they are the same as 'src', 'src_pos', 'dst'.
-
- BLOCK_COMMENT("scale indexes to element size");
- __ sll_ptr(src_pos, G3_elsize, src_pos);
- __ sll_ptr(dst_pos, G3_elsize, dst_pos);
- __ add(src, src_pos, from); // src_addr
- __ add(dst, dst_pos, to); // dst_addr
-
- BLOCK_COMMENT("choose copy loop based on element size");
- __ cmp(G3_elsize, 0);
- __ br(Assembler::equal, true, Assembler::pt, entry_jbyte_arraycopy);
- __ delayed()->signx(length, count); // length
-
- __ cmp(G3_elsize, LogBytesPerShort);
- __ br(Assembler::equal, true, Assembler::pt, entry_jshort_arraycopy);
- __ delayed()->signx(length, count); // length
-
- __ cmp(G3_elsize, LogBytesPerInt);
- __ br(Assembler::equal, true, Assembler::pt, entry_jint_arraycopy);
- __ delayed()->signx(length, count); // length
-#ifdef ASSERT
- { Label L;
- __ cmp_and_br_short(G3_elsize, LogBytesPerLong, Assembler::equal, Assembler::pt, L);
- __ stop("must be long copy, but elsize is wrong");
- __ bind(L);
- }
-#endif
- __ br(Assembler::always, false, Assembler::pt, entry_jlong_arraycopy);
- __ delayed()->signx(length, count); // length
-
- // ObjArrayKlass
- __ BIND(L_objArray);
- // live at this point: G3_src_klass, G4_dst_klass, src[_pos], dst[_pos], length
-
- Label L_plain_copy, L_checkcast_copy;
- // test array classes for subtyping
- __ cmp(G3_src_klass, G4_dst_klass); // usual case is exact equality
- __ brx(Assembler::notEqual, true, Assembler::pn, L_checkcast_copy);
- __ delayed()->lduw(G4_dst_klass, lh_offset, O5_temp); // hoisted from below
-
- // Identically typed arrays can be copied without element-wise checks.
- arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
- O5_temp, G5_lh, L_failed);
-
- __ add(src, arrayOopDesc::base_offset_in_bytes(T_OBJECT), src); //src offset
- __ add(dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT), dst); //dst offset
- __ sll_ptr(src_pos, LogBytesPerHeapOop, src_pos);
- __ sll_ptr(dst_pos, LogBytesPerHeapOop, dst_pos);
- __ add(src, src_pos, from); // src_addr
- __ add(dst, dst_pos, to); // dst_addr
- __ BIND(L_plain_copy);
- __ br(Assembler::always, false, Assembler::pt, entry_oop_arraycopy);
- __ delayed()->signx(length, count); // length
-
- __ BIND(L_checkcast_copy);
- // live at this point: G3_src_klass, G4_dst_klass
- {
- // Before looking at dst.length, make sure dst is also an objArray.
- // lduw(G4_dst_klass, lh_offset, O5_temp); // hoisted to delay slot
- __ cmp(G5_lh, O5_temp);
- __ br(Assembler::notEqual, false, Assembler::pn, L_failed);
-
- // It is safe to examine both src.length and dst.length.
- __ delayed(); // match next insn to prev branch
- arraycopy_range_checks(src, src_pos, dst, dst_pos, length,
- O5_temp, G5_lh, L_failed);
-
- // Marshal the base address arguments now, freeing registers.
- __ add(src, arrayOopDesc::base_offset_in_bytes(T_OBJECT), src); //src offset
- __ add(dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT), dst); //dst offset
- __ sll_ptr(src_pos, LogBytesPerHeapOop, src_pos);
- __ sll_ptr(dst_pos, LogBytesPerHeapOop, dst_pos);
- __ add(src, src_pos, from); // src_addr
- __ add(dst, dst_pos, to); // dst_addr
- __ signx(length, count); // length (reloaded)
-
- Register sco_temp = O3; // this register is free now
- assert_different_registers(from, to, count, sco_temp,
- G4_dst_klass, G3_src_klass);
-
- // Generate the type check.
- int sco_offset = in_bytes(Klass::super_check_offset_offset());
- __ lduw(G4_dst_klass, sco_offset, sco_temp);
- generate_type_check(G3_src_klass, sco_temp, G4_dst_klass,
- O5_temp, L_plain_copy);
-
- // Fetch destination element klass from the ObjArrayKlass header.
- int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
-
- // the checkcast_copy loop needs two extra arguments:
- __ ld_ptr(G4_dst_klass, ek_offset, O4); // dest elem klass
- // lduw(O4, sco_offset, O3); // sco of elem klass
-
- __ br(Assembler::always, false, Assembler::pt, entry_checkcast_arraycopy);
- __ delayed()->lduw(O4, sco_offset, O3);
- }
-
- __ BIND(L_failed);
- __ retl();
- __ delayed()->sub(G0, 1, O0); // return -1
- return start;
- }
-
- //
- // Generate stub for heap zeroing.
- // "to" address is aligned to jlong (8 bytes).
- //
- // Arguments for generated stub:
- // to: O0
- // count: O1 treated as signed (count of HeapWord)
- // count could be 0
- //
- address generate_zero_aligned_words(const char* name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- const Register to = O0; // source array address
- const Register count = O1; // HeapWords count
- const Register temp = O2; // scratch
-
- Label Ldone;
- __ sllx(count, LogHeapWordSize, count); // to bytes count
- // Use BIS for zeroing
- __ bis_zeroing(to, count, temp, Ldone);
- __ bind(Ldone);
- __ retl();
- __ delayed()->nop();
- return start;
-}
-
- void generate_arraycopy_stubs() {
- address entry;
- address entry_jbyte_arraycopy;
- address entry_jshort_arraycopy;
- address entry_jint_arraycopy;
- address entry_oop_arraycopy;
- address entry_jlong_arraycopy;
- address entry_checkcast_arraycopy;
-
- address ucm_common_error_exit = generate_unsafecopy_common_error_exit();
- UnsafeCopyMemory::set_common_exit_stub_pc(ucm_common_error_exit);
-
- //*** jbyte
- // Always need aligned and unaligned versions
- StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(false, &entry,
- "jbyte_disjoint_arraycopy");
- StubRoutines::_jbyte_arraycopy = generate_conjoint_byte_copy(false, entry,
- &entry_jbyte_arraycopy,
- "jbyte_arraycopy");
- StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(true, &entry,
- "arrayof_jbyte_disjoint_arraycopy");
- StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_byte_copy(true, entry, NULL,
- "arrayof_jbyte_arraycopy");
-
- //*** jshort
- // Always need aligned and unaligned versions
- StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_short_copy(false, &entry,
- "jshort_disjoint_arraycopy");
- StubRoutines::_jshort_arraycopy = generate_conjoint_short_copy(false, entry,
- &entry_jshort_arraycopy,
- "jshort_arraycopy");
- StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_short_copy(true, &entry,
- "arrayof_jshort_disjoint_arraycopy");
- StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_short_copy(true, entry, NULL,
- "arrayof_jshort_arraycopy");
-
- //*** jint
- // Aligned versions
- StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_int_copy(true, &entry,
- "arrayof_jint_disjoint_arraycopy");
- StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_int_copy(true, entry, &entry_jint_arraycopy,
- "arrayof_jint_arraycopy");
- // In 64 bit we need both aligned and unaligned versions of jint arraycopy.
- // entry_jint_arraycopy always points to the unaligned version (notice that we overwrite it).
- StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_int_copy(false, &entry,
- "jint_disjoint_arraycopy");
- StubRoutines::_jint_arraycopy = generate_conjoint_int_copy(false, entry,
- &entry_jint_arraycopy,
- "jint_arraycopy");
-
- //*** jlong
- // It is always aligned
- StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_long_copy(true, &entry,
- "arrayof_jlong_disjoint_arraycopy");
- StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_long_copy(true, entry, &entry_jlong_arraycopy,
- "arrayof_jlong_arraycopy");
- StubRoutines::_jlong_disjoint_arraycopy = StubRoutines::_arrayof_jlong_disjoint_arraycopy;
- StubRoutines::_jlong_arraycopy = StubRoutines::_arrayof_jlong_arraycopy;
-
-
- //*** oops
- // Aligned versions
- StubRoutines::_arrayof_oop_disjoint_arraycopy = generate_disjoint_oop_copy(true, &entry,
- "arrayof_oop_disjoint_arraycopy");
- StubRoutines::_arrayof_oop_arraycopy = generate_conjoint_oop_copy(true, entry, &entry_oop_arraycopy,
- "arrayof_oop_arraycopy");
- // Aligned versions without pre-barriers
- StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = generate_disjoint_oop_copy(true, &entry,
- "arrayof_oop_disjoint_arraycopy_uninit",
- /*dest_uninitialized*/true);
- StubRoutines::_arrayof_oop_arraycopy_uninit = generate_conjoint_oop_copy(true, entry, NULL,
- "arrayof_oop_arraycopy_uninit",
- /*dest_uninitialized*/true);
- if (UseCompressedOops) {
- // With compressed oops we need unaligned versions, notice that we overwrite entry_oop_arraycopy.
- StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_oop_copy(false, &entry,
- "oop_disjoint_arraycopy");
- StubRoutines::_oop_arraycopy = generate_conjoint_oop_copy(false, entry, &entry_oop_arraycopy,
- "oop_arraycopy");
- // Unaligned versions without pre-barriers
- StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_oop_copy(false, &entry,
- "oop_disjoint_arraycopy_uninit",
- /*dest_uninitialized*/true);
- StubRoutines::_oop_arraycopy_uninit = generate_conjoint_oop_copy(false, entry, NULL,
- "oop_arraycopy_uninit",
- /*dest_uninitialized*/true);
- } else {
- // oop arraycopy is always aligned on 32bit and 64bit without compressed oops
- StubRoutines::_oop_disjoint_arraycopy = StubRoutines::_arrayof_oop_disjoint_arraycopy;
- StubRoutines::_oop_arraycopy = StubRoutines::_arrayof_oop_arraycopy;
- StubRoutines::_oop_disjoint_arraycopy_uninit = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit;
- StubRoutines::_oop_arraycopy_uninit = StubRoutines::_arrayof_oop_arraycopy_uninit;
- }
-
- StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", &entry_checkcast_arraycopy);
- StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", NULL,
- /*dest_uninitialized*/true);
-
- StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy",
- entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_jlong_arraycopy);
- StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy",
- entry_jbyte_arraycopy,
- entry_jshort_arraycopy,
- entry_jint_arraycopy,
- entry_oop_arraycopy,
- entry_jlong_arraycopy,
- entry_checkcast_arraycopy);
-
- StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill");
- StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill");
- StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill");
- StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill");
- StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill");
- StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill");
-
- if (UseBlockZeroing) {
- StubRoutines::_zero_aligned_words = generate_zero_aligned_words("zero_aligned_words");
- }
- }
-
- address generate_aescrypt_encryptBlock() {
- // required since we read expanded key 'int' array starting first element without alignment considerations
- assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0,
- "the following code assumes that first element of an int array is aligned to 8 bytes");
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock");
- Label L_load_misaligned_input, L_load_expanded_key, L_doLast128bit, L_storeOutput, L_store_misaligned_output;
- address start = __ pc();
- Register from = O0; // source byte array
- Register to = O1; // destination byte array
- Register key = O2; // expanded key array
- const Register keylen = O4; //reg for storing expanded key array length
-
- // read expanded key length
- __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0);
-
- // Method to address arbitrary alignment for load instructions:
- // Check last 3 bits of 'from' address to see if it is aligned to 8-byte boundary
- // If zero/aligned then continue with double FP load instructions
- // If not zero/mis-aligned then alignaddr will set GSR.align with number of bytes to skip during faligndata
- // alignaddr will also convert arbitrary aligned 'from' address to nearest 8-byte aligned address
- // load 3 * 8-byte components (to read 16 bytes input) in 3 different FP regs starting at this aligned address
- // faligndata will then extract (based on GSR.align value) the appropriate 8 bytes from the 2 source regs
-
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input);
- __ delayed()->alignaddr(from, G0, from);
-
- // aligned case: load input into F54-F56
- __ ldf(FloatRegisterImpl::D, from, 0, F54);
- __ ldf(FloatRegisterImpl::D, from, 8, F56);
- __ ba_short(L_load_expanded_key);
-
- __ BIND(L_load_misaligned_input);
- __ ldf(FloatRegisterImpl::D, from, 0, F54);
- __ ldf(FloatRegisterImpl::D, from, 8, F56);
- __ ldf(FloatRegisterImpl::D, from, 16, F58);
- __ faligndata(F54, F56, F54);
- __ faligndata(F56, F58, F56);
-
- __ BIND(L_load_expanded_key);
- // Since we load expanded key buffers starting first element, 8-byte alignment is guaranteed
- for ( int i = 0; i <= 38; i += 2 ) {
- __ ldf(FloatRegisterImpl::D, key, i*4, as_FloatRegister(i));
- }
-
- // perform cipher transformation
- __ fxor(FloatRegisterImpl::D, F0, F54, F54);
- __ fxor(FloatRegisterImpl::D, F2, F56, F56);
- // rounds 1 through 8
- for ( int i = 4; i <= 28; i += 8 ) {
- __ aes_eround01(as_FloatRegister(i), F54, F56, F58);
- __ aes_eround23(as_FloatRegister(i+2), F54, F56, F60);
- __ aes_eround01(as_FloatRegister(i+4), F58, F60, F54);
- __ aes_eround23(as_FloatRegister(i+6), F58, F60, F56);
- }
- __ aes_eround01(F36, F54, F56, F58); //round 9
- __ aes_eround23(F38, F54, F56, F60);
-
- // 128-bit original key size
- __ cmp_and_brx_short(keylen, 44, Assembler::equal, Assembler::pt, L_doLast128bit);
-
- for ( int i = 40; i <= 50; i += 2 ) {
- __ ldf(FloatRegisterImpl::D, key, i*4, as_FloatRegister(i) );
- }
- __ aes_eround01(F40, F58, F60, F54); //round 10
- __ aes_eround23(F42, F58, F60, F56);
- __ aes_eround01(F44, F54, F56, F58); //round 11
- __ aes_eround23(F46, F54, F56, F60);
-
- // 192-bit original key size
- __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pt, L_storeOutput);
-
- __ ldf(FloatRegisterImpl::D, key, 208, F52);
- __ aes_eround01(F48, F58, F60, F54); //round 12
- __ aes_eround23(F50, F58, F60, F56);
- __ ldf(FloatRegisterImpl::D, key, 216, F46);
- __ ldf(FloatRegisterImpl::D, key, 224, F48);
- __ ldf(FloatRegisterImpl::D, key, 232, F50);
- __ aes_eround01(F52, F54, F56, F58); //round 13
- __ aes_eround23(F46, F54, F56, F60);
- __ ba_short(L_storeOutput);
-
- __ BIND(L_doLast128bit);
- __ ldf(FloatRegisterImpl::D, key, 160, F48);
- __ ldf(FloatRegisterImpl::D, key, 168, F50);
-
- __ BIND(L_storeOutput);
- // perform last round of encryption common for all key sizes
- __ aes_eround01_l(F48, F58, F60, F54); //last round
- __ aes_eround23_l(F50, F58, F60, F56);
-
- // Method to address arbitrary alignment for store instructions:
- // Check last 3 bits of 'dest' address to see if it is aligned to 8-byte boundary
- // If zero/aligned then continue with double FP store instructions
- // If not zero/mis-aligned then edge8n will generate edge mask in result reg (O3 in below case)
- // Example: If dest address is 0x07 and nearest 8-byte aligned address is 0x00 then edge mask will be 00000001
- // Compute (8-n) where n is # of bytes skipped by partial store(stpartialf) inst from edge mask, n=7 in this case
- // We get the value of n from the andcc that checks 'dest' alignment. n is available in O5 in below case.
- // Set GSR.align to (8-n) using alignaddr
- // Circular byte shift store values by n places so that the original bytes are at correct position for stpartialf
- // Set the arbitrarily aligned 'dest' address to nearest 8-byte aligned address
- // Store (partial) the original first (8-n) bytes starting at the original 'dest' address
- // Negate the edge mask so that the subsequent stpartialf can store the original (8-n-1)th through 8th bytes at appropriate address
- // We need to execute this process for both the 8-byte result values
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, O5);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output);
- __ delayed()->edge8n(to, G0, O3);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F54, to, 0);
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::D, F56, to, 8);
-
- __ BIND(L_store_misaligned_output);
- __ add(to, 8, O4);
- __ mov(8, O2);
- __ sub(O2, O5, O2);
- __ alignaddr(O2, G0, O2);
- __ faligndata(F54, F54, F54);
- __ faligndata(F56, F56, F56);
- __ and3(to, -8, to);
- __ and3(O4, -8, O4);
- __ stpartialf(to, O3, F54, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(O4, O3, F56, Assembler::ASI_PST8_PRIMARY);
- __ add(to, 8, to);
- __ add(O4, 8, O4);
- __ orn(G0, O3, O3);
- __ stpartialf(to, O3, F54, Assembler::ASI_PST8_PRIMARY);
- __ retl();
- __ delayed()->stpartialf(O4, O3, F56, Assembler::ASI_PST8_PRIMARY);
-
- return start;
- }
-
- address generate_aescrypt_decryptBlock() {
- assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0,
- "the following code assumes that first element of an int array is aligned to 8 bytes");
- // required since we read original key 'byte' array as well in the decryption stubs
- assert((arrayOopDesc::base_offset_in_bytes(T_BYTE) & 7) == 0,
- "the following code assumes that first element of a byte array is aligned to 8 bytes");
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock");
- address start = __ pc();
- Label L_load_misaligned_input, L_load_original_key, L_expand192bit, L_expand256bit, L_reload_misaligned_input;
- Label L_256bit_transform, L_common_transform, L_store_misaligned_output;
- Register from = O0; // source byte array
- Register to = O1; // destination byte array
- Register key = O2; // expanded key array
- Register original_key = O3; // original key array only required during decryption
- const Register keylen = O4; // reg for storing expanded key array length
-
- // read expanded key array length
- __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0);
-
- // save 'from' since we may need to recheck alignment in case of 256-bit decryption
- __ mov(from, G1);
-
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input);
- __ delayed()->alignaddr(from, G0, from);
-
- // aligned case: load input into F52-F54
- __ ldf(FloatRegisterImpl::D, from, 0, F52);
- __ ldf(FloatRegisterImpl::D, from, 8, F54);
- __ ba_short(L_load_original_key);
-
- __ BIND(L_load_misaligned_input);
- __ ldf(FloatRegisterImpl::D, from, 0, F52);
- __ ldf(FloatRegisterImpl::D, from, 8, F54);
- __ ldf(FloatRegisterImpl::D, from, 16, F56);
- __ faligndata(F52, F54, F52);
- __ faligndata(F54, F56, F54);
-
- __ BIND(L_load_original_key);
- // load original key from SunJCE expanded decryption key
- // Since we load original key buffer starting first element, 8-byte alignment is guaranteed
- for ( int i = 0; i <= 3; i++ ) {
- __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i));
- }
-
- // 256-bit original key size
- __ cmp_and_brx_short(keylen, 60, Assembler::equal, Assembler::pn, L_expand256bit);
-
- // 192-bit original key size
- __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_expand192bit);
-
- // 128-bit original key size
- // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions
- for ( int i = 0; i <= 36; i += 4 ) {
- __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+2), i/4, as_FloatRegister(i+4));
- __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+4), as_FloatRegister(i+6));
- }
-
- // perform 128-bit key specific inverse cipher transformation
- __ fxor(FloatRegisterImpl::D, F42, F54, F54);
- __ fxor(FloatRegisterImpl::D, F40, F52, F52);
- __ ba_short(L_common_transform);
-
- __ BIND(L_expand192bit);
-
- // start loading rest of the 192-bit key
- __ ldf(FloatRegisterImpl::S, original_key, 16, F4);
- __ ldf(FloatRegisterImpl::S, original_key, 20, F5);
-
- // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions
- for ( int i = 0; i <= 36; i += 6 ) {
- __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+4), i/6, as_FloatRegister(i+6));
- __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+6), as_FloatRegister(i+8));
- __ aes_kexpand2(as_FloatRegister(i+4), as_FloatRegister(i+8), as_FloatRegister(i+10));
- }
- __ aes_kexpand1(F42, F46, 7, F48);
- __ aes_kexpand2(F44, F48, F50);
-
- // perform 192-bit key specific inverse cipher transformation
- __ fxor(FloatRegisterImpl::D, F50, F54, F54);
- __ fxor(FloatRegisterImpl::D, F48, F52, F52);
- __ aes_dround23(F46, F52, F54, F58);
- __ aes_dround01(F44, F52, F54, F56);
- __ aes_dround23(F42, F56, F58, F54);
- __ aes_dround01(F40, F56, F58, F52);
- __ ba_short(L_common_transform);
-
- __ BIND(L_expand256bit);
-
- // load rest of the 256-bit key
- for ( int i = 4; i <= 7; i++ ) {
- __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i));
- }
-
- // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions
- for ( int i = 0; i <= 40; i += 8 ) {
- __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+6), i/8, as_FloatRegister(i+8));
- __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+8), as_FloatRegister(i+10));
- __ aes_kexpand0(as_FloatRegister(i+4), as_FloatRegister(i+10), as_FloatRegister(i+12));
- __ aes_kexpand2(as_FloatRegister(i+6), as_FloatRegister(i+12), as_FloatRegister(i+14));
- }
- __ aes_kexpand1(F48, F54, 6, F56);
- __ aes_kexpand2(F50, F56, F58);
-
- for ( int i = 0; i <= 6; i += 2 ) {
- __ fsrc2(FloatRegisterImpl::D, as_FloatRegister(58-i), as_FloatRegister(i));
- }
-
- // reload original 'from' address
- __ mov(G1, from);
-
- // re-check 8-byte alignment
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_reload_misaligned_input);
- __ delayed()->alignaddr(from, G0, from);
-
- // aligned case: load input into F52-F54
- __ ldf(FloatRegisterImpl::D, from, 0, F52);
- __ ldf(FloatRegisterImpl::D, from, 8, F54);
- __ ba_short(L_256bit_transform);
-
- __ BIND(L_reload_misaligned_input);
- __ ldf(FloatRegisterImpl::D, from, 0, F52);
- __ ldf(FloatRegisterImpl::D, from, 8, F54);
- __ ldf(FloatRegisterImpl::D, from, 16, F56);
- __ faligndata(F52, F54, F52);
- __ faligndata(F54, F56, F54);
-
- // perform 256-bit key specific inverse cipher transformation
- __ BIND(L_256bit_transform);
- __ fxor(FloatRegisterImpl::D, F0, F54, F54);
- __ fxor(FloatRegisterImpl::D, F2, F52, F52);
- __ aes_dround23(F4, F52, F54, F58);
- __ aes_dround01(F6, F52, F54, F56);
- __ aes_dround23(F50, F56, F58, F54);
- __ aes_dround01(F48, F56, F58, F52);
- __ aes_dround23(F46, F52, F54, F58);
- __ aes_dround01(F44, F52, F54, F56);
- __ aes_dround23(F42, F56, F58, F54);
- __ aes_dround01(F40, F56, F58, F52);
-
- for ( int i = 0; i <= 7; i++ ) {
- __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i));
- }
-
- // perform inverse cipher transformations common for all key sizes
- __ BIND(L_common_transform);
- for ( int i = 38; i >= 6; i -= 8 ) {
- __ aes_dround23(as_FloatRegister(i), F52, F54, F58);
- __ aes_dround01(as_FloatRegister(i-2), F52, F54, F56);
- if ( i != 6) {
- __ aes_dround23(as_FloatRegister(i-4), F56, F58, F54);
- __ aes_dround01(as_FloatRegister(i-6), F56, F58, F52);
- } else {
- __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F54);
- __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F52);
- }
- }
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, O5);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output);
- __ delayed()->edge8n(to, G0, O3);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F52, to, 0);
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::D, F54, to, 8);
-
- __ BIND(L_store_misaligned_output);
- __ add(to, 8, O4);
- __ mov(8, O2);
- __ sub(O2, O5, O2);
- __ alignaddr(O2, G0, O2);
- __ faligndata(F52, F52, F52);
- __ faligndata(F54, F54, F54);
- __ and3(to, -8, to);
- __ and3(O4, -8, O4);
- __ stpartialf(to, O3, F52, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(O4, O3, F54, Assembler::ASI_PST8_PRIMARY);
- __ add(to, 8, to);
- __ add(O4, 8, O4);
- __ orn(G0, O3, O3);
- __ stpartialf(to, O3, F52, Assembler::ASI_PST8_PRIMARY);
- __ retl();
- __ delayed()->stpartialf(O4, O3, F54, Assembler::ASI_PST8_PRIMARY);
-
- return start;
- }
-
- address generate_cipherBlockChaining_encryptAESCrypt() {
- assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0,
- "the following code assumes that first element of an int array is aligned to 8 bytes");
- assert((arrayOopDesc::base_offset_in_bytes(T_BYTE) & 7) == 0,
- "the following code assumes that first element of a byte array is aligned to 8 bytes");
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt");
- Label L_cbcenc128, L_load_misaligned_input_128bit, L_128bit_transform, L_store_misaligned_output_128bit;
- Label L_check_loop_end_128bit, L_cbcenc192, L_load_misaligned_input_192bit, L_192bit_transform;
- Label L_store_misaligned_output_192bit, L_check_loop_end_192bit, L_cbcenc256, L_load_misaligned_input_256bit;
- Label L_256bit_transform, L_store_misaligned_output_256bit, L_check_loop_end_256bit;
- address start = __ pc();
- Register from = I0; // source byte array
- Register to = I1; // destination byte array
- Register key = I2; // expanded key array
- Register rvec = I3; // init vector
- const Register len_reg = I4; // cipher length
- const Register keylen = I5; // reg for storing expanded key array length
-
- __ save_frame(0);
- // save cipher len to return in the end
- __ mov(len_reg, L0);
-
- // read expanded key length
- __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0);
-
- // load initial vector, 8-byte alignment is guranteed
- __ ldf(FloatRegisterImpl::D, rvec, 0, F60);
- __ ldf(FloatRegisterImpl::D, rvec, 8, F62);
- // load key, 8-byte alignment is guranteed
- __ ldx(key,0,G1);
- __ ldx(key,8,G5);
-
- // start loading expanded key, 8-byte alignment is guranteed
- for ( int i = 0, j = 16; i <= 38; i += 2, j += 8 ) {
- __ ldf(FloatRegisterImpl::D, key, j, as_FloatRegister(i));
- }
-
- // 128-bit original key size
- __ cmp_and_brx_short(keylen, 44, Assembler::equal, Assembler::pt, L_cbcenc128);
-
- for ( int i = 40, j = 176; i <= 46; i += 2, j += 8 ) {
- __ ldf(FloatRegisterImpl::D, key, j, as_FloatRegister(i));
- }
-
- // 192-bit original key size
- __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pt, L_cbcenc192);
-
- for ( int i = 48, j = 208; i <= 54; i += 2, j += 8 ) {
- __ ldf(FloatRegisterImpl::D, key, j, as_FloatRegister(i));
- }
-
- // 256-bit original key size
- __ ba_short(L_cbcenc256);
-
- __ align(OptoLoopAlignment);
- __ BIND(L_cbcenc128);
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_128bit);
- __ delayed()->mov(from, L1); // save original 'from' address before alignaddr
-
- // aligned case: load input into G3 and G4
- __ ldx(from,0,G3);
- __ ldx(from,8,G4);
- __ ba_short(L_128bit_transform);
-
- __ BIND(L_load_misaligned_input_128bit);
- // can clobber F48, F50 and F52 as they are not used in 128 and 192-bit key encryption
- __ alignaddr(from, G0, from);
- __ ldf(FloatRegisterImpl::D, from, 0, F48);
- __ ldf(FloatRegisterImpl::D, from, 8, F50);
- __ ldf(FloatRegisterImpl::D, from, 16, F52);
- __ faligndata(F48, F50, F48);
- __ faligndata(F50, F52, F50);
- __ movdtox(F48, G3);
- __ movdtox(F50, G4);
- __ mov(L1, from);
-
- __ BIND(L_128bit_transform);
- __ xor3(G1,G3,G3);
- __ xor3(G5,G4,G4);
- __ movxtod(G3,F56);
- __ movxtod(G4,F58);
- __ fxor(FloatRegisterImpl::D, F60, F56, F60);
- __ fxor(FloatRegisterImpl::D, F62, F58, F62);
-
- // TEN_EROUNDS
- for ( int i = 0; i <= 32; i += 8 ) {
- __ aes_eround01(as_FloatRegister(i), F60, F62, F56);
- __ aes_eround23(as_FloatRegister(i+2), F60, F62, F58);
- if (i != 32 ) {
- __ aes_eround01(as_FloatRegister(i+4), F56, F58, F60);
- __ aes_eround23(as_FloatRegister(i+6), F56, F58, F62);
- } else {
- __ aes_eround01_l(as_FloatRegister(i+4), F56, F58, F60);
- __ aes_eround23_l(as_FloatRegister(i+6), F56, F58, F62);
- }
- }
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, L1);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_128bit);
- __ delayed()->edge8n(to, G0, L2);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F60, to, 0);
- __ stf(FloatRegisterImpl::D, F62, to, 8);
- __ ba_short(L_check_loop_end_128bit);
-
- __ BIND(L_store_misaligned_output_128bit);
- __ add(to, 8, L3);
- __ mov(8, L4);
- __ sub(L4, L1, L4);
- __ alignaddr(L4, G0, L4);
- // save cipher text before circular right shift
- // as it needs to be stored as iv for next block (see code before next retl)
- __ movdtox(F60, L6);
- __ movdtox(F62, L7);
- __ faligndata(F60, F60, F60);
- __ faligndata(F62, F62, F62);
- __ mov(to, L5);
- __ and3(to, -8, to);
- __ and3(L3, -8, L3);
- __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY);
- __ add(to, 8, to);
- __ add(L3, 8, L3);
- __ orn(G0, L2, L2);
- __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY);
- __ mov(L5, to);
- __ movxtod(L6, F60);
- __ movxtod(L7, F62);
-
- __ BIND(L_check_loop_end_128bit);
- __ add(from, 16, from);
- __ add(to, 16, to);
- __ subcc(len_reg, 16, len_reg);
- __ br(Assembler::notEqual, false, Assembler::pt, L_cbcenc128);
- __ delayed()->nop();
- // re-init intial vector for next block, 8-byte alignment is guaranteed
- __ stf(FloatRegisterImpl::D, F60, rvec, 0);
- __ stf(FloatRegisterImpl::D, F62, rvec, 8);
- __ mov(L0, I0);
- __ ret();
- __ delayed()->restore();
-
- __ align(OptoLoopAlignment);
- __ BIND(L_cbcenc192);
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_192bit);
- __ delayed()->mov(from, L1); // save original 'from' address before alignaddr
-
- // aligned case: load input into G3 and G4
- __ ldx(from,0,G3);
- __ ldx(from,8,G4);
- __ ba_short(L_192bit_transform);
-
- __ BIND(L_load_misaligned_input_192bit);
- // can clobber F48, F50 and F52 as they are not used in 128 and 192-bit key encryption
- __ alignaddr(from, G0, from);
- __ ldf(FloatRegisterImpl::D, from, 0, F48);
- __ ldf(FloatRegisterImpl::D, from, 8, F50);
- __ ldf(FloatRegisterImpl::D, from, 16, F52);
- __ faligndata(F48, F50, F48);
- __ faligndata(F50, F52, F50);
- __ movdtox(F48, G3);
- __ movdtox(F50, G4);
- __ mov(L1, from);
-
- __ BIND(L_192bit_transform);
- __ xor3(G1,G3,G3);
- __ xor3(G5,G4,G4);
- __ movxtod(G3,F56);
- __ movxtod(G4,F58);
- __ fxor(FloatRegisterImpl::D, F60, F56, F60);
- __ fxor(FloatRegisterImpl::D, F62, F58, F62);
-
- // TWELEVE_EROUNDS
- for ( int i = 0; i <= 40; i += 8 ) {
- __ aes_eround01(as_FloatRegister(i), F60, F62, F56);
- __ aes_eround23(as_FloatRegister(i+2), F60, F62, F58);
- if (i != 40 ) {
- __ aes_eround01(as_FloatRegister(i+4), F56, F58, F60);
- __ aes_eround23(as_FloatRegister(i+6), F56, F58, F62);
- } else {
- __ aes_eround01_l(as_FloatRegister(i+4), F56, F58, F60);
- __ aes_eround23_l(as_FloatRegister(i+6), F56, F58, F62);
- }
- }
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, L1);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_192bit);
- __ delayed()->edge8n(to, G0, L2);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F60, to, 0);
- __ stf(FloatRegisterImpl::D, F62, to, 8);
- __ ba_short(L_check_loop_end_192bit);
-
- __ BIND(L_store_misaligned_output_192bit);
- __ add(to, 8, L3);
- __ mov(8, L4);
- __ sub(L4, L1, L4);
- __ alignaddr(L4, G0, L4);
- __ movdtox(F60, L6);
- __ movdtox(F62, L7);
- __ faligndata(F60, F60, F60);
- __ faligndata(F62, F62, F62);
- __ mov(to, L5);
- __ and3(to, -8, to);
- __ and3(L3, -8, L3);
- __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY);
- __ add(to, 8, to);
- __ add(L3, 8, L3);
- __ orn(G0, L2, L2);
- __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY);
- __ mov(L5, to);
- __ movxtod(L6, F60);
- __ movxtod(L7, F62);
-
- __ BIND(L_check_loop_end_192bit);
- __ add(from, 16, from);
- __ subcc(len_reg, 16, len_reg);
- __ add(to, 16, to);
- __ br(Assembler::notEqual, false, Assembler::pt, L_cbcenc192);
- __ delayed()->nop();
- // re-init intial vector for next block, 8-byte alignment is guaranteed
- __ stf(FloatRegisterImpl::D, F60, rvec, 0);
- __ stf(FloatRegisterImpl::D, F62, rvec, 8);
- __ mov(L0, I0);
- __ ret();
- __ delayed()->restore();
-
- __ align(OptoLoopAlignment);
- __ BIND(L_cbcenc256);
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_256bit);
- __ delayed()->mov(from, L1); // save original 'from' address before alignaddr
-
- // aligned case: load input into G3 and G4
- __ ldx(from,0,G3);
- __ ldx(from,8,G4);
- __ ba_short(L_256bit_transform);
-
- __ BIND(L_load_misaligned_input_256bit);
- // cannot clobber F48, F50 and F52. F56, F58 can be used though
- __ alignaddr(from, G0, from);
- __ movdtox(F60, L2); // save F60 before overwriting
- __ ldf(FloatRegisterImpl::D, from, 0, F56);
- __ ldf(FloatRegisterImpl::D, from, 8, F58);
- __ ldf(FloatRegisterImpl::D, from, 16, F60);
- __ faligndata(F56, F58, F56);
- __ faligndata(F58, F60, F58);
- __ movdtox(F56, G3);
- __ movdtox(F58, G4);
- __ mov(L1, from);
- __ movxtod(L2, F60);
-
- __ BIND(L_256bit_transform);
- __ xor3(G1,G3,G3);
- __ xor3(G5,G4,G4);
- __ movxtod(G3,F56);
- __ movxtod(G4,F58);
- __ fxor(FloatRegisterImpl::D, F60, F56, F60);
- __ fxor(FloatRegisterImpl::D, F62, F58, F62);
-
- // FOURTEEN_EROUNDS
- for ( int i = 0; i <= 48; i += 8 ) {
- __ aes_eround01(as_FloatRegister(i), F60, F62, F56);
- __ aes_eround23(as_FloatRegister(i+2), F60, F62, F58);
- if (i != 48 ) {
- __ aes_eround01(as_FloatRegister(i+4), F56, F58, F60);
- __ aes_eround23(as_FloatRegister(i+6), F56, F58, F62);
- } else {
- __ aes_eround01_l(as_FloatRegister(i+4), F56, F58, F60);
- __ aes_eround23_l(as_FloatRegister(i+6), F56, F58, F62);
- }
- }
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, L1);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_256bit);
- __ delayed()->edge8n(to, G0, L2);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F60, to, 0);
- __ stf(FloatRegisterImpl::D, F62, to, 8);
- __ ba_short(L_check_loop_end_256bit);
-
- __ BIND(L_store_misaligned_output_256bit);
- __ add(to, 8, L3);
- __ mov(8, L4);
- __ sub(L4, L1, L4);
- __ alignaddr(L4, G0, L4);
- __ movdtox(F60, L6);
- __ movdtox(F62, L7);
- __ faligndata(F60, F60, F60);
- __ faligndata(F62, F62, F62);
- __ mov(to, L5);
- __ and3(to, -8, to);
- __ and3(L3, -8, L3);
- __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY);
- __ add(to, 8, to);
- __ add(L3, 8, L3);
- __ orn(G0, L2, L2);
- __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY);
- __ mov(L5, to);
- __ movxtod(L6, F60);
- __ movxtod(L7, F62);
-
- __ BIND(L_check_loop_end_256bit);
- __ add(from, 16, from);
- __ subcc(len_reg, 16, len_reg);
- __ add(to, 16, to);
- __ br(Assembler::notEqual, false, Assembler::pt, L_cbcenc256);
- __ delayed()->nop();
- // re-init intial vector for next block, 8-byte alignment is guaranteed
- __ stf(FloatRegisterImpl::D, F60, rvec, 0);
- __ stf(FloatRegisterImpl::D, F62, rvec, 8);
- __ mov(L0, I0);
- __ ret();
- __ delayed()->restore();
-
- return start;
- }
-
- address generate_cipherBlockChaining_decryptAESCrypt_Parallel() {
- assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0,
- "the following code assumes that first element of an int array is aligned to 8 bytes");
- assert((arrayOopDesc::base_offset_in_bytes(T_BYTE) & 7) == 0,
- "the following code assumes that first element of a byte array is aligned to 8 bytes");
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
- Label L_cbcdec_end, L_expand192bit, L_expand256bit, L_dec_first_block_start;
- Label L_dec_first_block128, L_dec_first_block192, L_dec_next2_blocks128, L_dec_next2_blocks192, L_dec_next2_blocks256;
- Label L_load_misaligned_input_first_block, L_transform_first_block, L_load_misaligned_next2_blocks128, L_transform_next2_blocks128;
- Label L_load_misaligned_next2_blocks192, L_transform_next2_blocks192, L_load_misaligned_next2_blocks256, L_transform_next2_blocks256;
- Label L_store_misaligned_output_first_block, L_check_decrypt_end, L_store_misaligned_output_next2_blocks128;
- Label L_check_decrypt_loop_end128, L_store_misaligned_output_next2_blocks192, L_check_decrypt_loop_end192;
- Label L_store_misaligned_output_next2_blocks256, L_check_decrypt_loop_end256;
- address start = __ pc();
- Register from = I0; // source byte array
- Register to = I1; // destination byte array
- Register key = I2; // expanded key array
- Register rvec = I3; // init vector
- const Register len_reg = I4; // cipher length
- const Register original_key = I5; // original key array only required during decryption
- const Register keylen = L6; // reg for storing expanded key array length
-
- __ save_frame(0); //args are read from I* registers since we save the frame in the beginning
- // save cipher len to return in the end
- __ mov(len_reg, L7);
-
- // load original key from SunJCE expanded decryption key
- // Since we load original key buffer starting first element, 8-byte alignment is guaranteed
- for ( int i = 0; i <= 3; i++ ) {
- __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i));
- }
-
- // load initial vector, 8-byte alignment is guaranteed
- __ ldx(rvec,0,L0);
- __ ldx(rvec,8,L1);
-
- // read expanded key array length
- __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0);
-
- // 256-bit original key size
- __ cmp_and_brx_short(keylen, 60, Assembler::equal, Assembler::pn, L_expand256bit);
-
- // 192-bit original key size
- __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_expand192bit);
-
- // 128-bit original key size
- // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions
- for ( int i = 0; i <= 36; i += 4 ) {
- __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+2), i/4, as_FloatRegister(i+4));
- __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+4), as_FloatRegister(i+6));
- }
-
- // load expanded key[last-1] and key[last] elements
- __ movdtox(F40,L2);
- __ movdtox(F42,L3);
-
- __ and3(len_reg, 16, L4);
- __ br_null_short(L4, Assembler::pt, L_dec_next2_blocks128);
- __ nop();
-
- __ ba_short(L_dec_first_block_start);
-
- __ BIND(L_expand192bit);
- // load rest of the 192-bit key
- __ ldf(FloatRegisterImpl::S, original_key, 16, F4);
- __ ldf(FloatRegisterImpl::S, original_key, 20, F5);
-
- // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions
- for ( int i = 0; i <= 36; i += 6 ) {
- __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+4), i/6, as_FloatRegister(i+6));
- __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+6), as_FloatRegister(i+8));
- __ aes_kexpand2(as_FloatRegister(i+4), as_FloatRegister(i+8), as_FloatRegister(i+10));
- }
- __ aes_kexpand1(F42, F46, 7, F48);
- __ aes_kexpand2(F44, F48, F50);
-
- // load expanded key[last-1] and key[last] elements
- __ movdtox(F48,L2);
- __ movdtox(F50,L3);
-
- __ and3(len_reg, 16, L4);
- __ br_null_short(L4, Assembler::pt, L_dec_next2_blocks192);
- __ nop();
-
- __ ba_short(L_dec_first_block_start);
-
- __ BIND(L_expand256bit);
- // load rest of the 256-bit key
- for ( int i = 4; i <= 7; i++ ) {
- __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i));
- }
-
- // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions
- for ( int i = 0; i <= 40; i += 8 ) {
- __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+6), i/8, as_FloatRegister(i+8));
- __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+8), as_FloatRegister(i+10));
- __ aes_kexpand0(as_FloatRegister(i+4), as_FloatRegister(i+10), as_FloatRegister(i+12));
- __ aes_kexpand2(as_FloatRegister(i+6), as_FloatRegister(i+12), as_FloatRegister(i+14));
- }
- __ aes_kexpand1(F48, F54, 6, F56);
- __ aes_kexpand2(F50, F56, F58);
-
- // load expanded key[last-1] and key[last] elements
- __ movdtox(F56,L2);
- __ movdtox(F58,L3);
-
- __ and3(len_reg, 16, L4);
- __ br_null_short(L4, Assembler::pt, L_dec_next2_blocks256);
-
- __ BIND(L_dec_first_block_start);
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_first_block);
- __ delayed()->mov(from, G1); // save original 'from' address before alignaddr
-
- // aligned case: load input into L4 and L5
- __ ldx(from,0,L4);
- __ ldx(from,8,L5);
- __ ba_short(L_transform_first_block);
-
- __ BIND(L_load_misaligned_input_first_block);
- __ alignaddr(from, G0, from);
- // F58, F60, F62 can be clobbered
- __ ldf(FloatRegisterImpl::D, from, 0, F58);
- __ ldf(FloatRegisterImpl::D, from, 8, F60);
- __ ldf(FloatRegisterImpl::D, from, 16, F62);
- __ faligndata(F58, F60, F58);
- __ faligndata(F60, F62, F60);
- __ movdtox(F58, L4);
- __ movdtox(F60, L5);
- __ mov(G1, from);
-
- __ BIND(L_transform_first_block);
- __ xor3(L2,L4,G1);
- __ movxtod(G1,F60);
- __ xor3(L3,L5,G1);
- __ movxtod(G1,F62);
-
- // 128-bit original key size
- __ cmp_and_brx_short(keylen, 44, Assembler::equal, Assembler::pn, L_dec_first_block128);
-
- // 192-bit original key size
- __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_dec_first_block192);
-
- __ aes_dround23(F54, F60, F62, F58);
- __ aes_dround01(F52, F60, F62, F56);
- __ aes_dround23(F50, F56, F58, F62);
- __ aes_dround01(F48, F56, F58, F60);
-
- __ BIND(L_dec_first_block192);
- __ aes_dround23(F46, F60, F62, F58);
- __ aes_dround01(F44, F60, F62, F56);
- __ aes_dround23(F42, F56, F58, F62);
- __ aes_dround01(F40, F56, F58, F60);
-
- __ BIND(L_dec_first_block128);
- for ( int i = 38; i >= 6; i -= 8 ) {
- __ aes_dround23(as_FloatRegister(i), F60, F62, F58);
- __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56);
- if ( i != 6) {
- __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62);
- __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60);
- } else {
- __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F62);
- __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F60);
- }
- }
-
- __ movxtod(L0,F56);
- __ movxtod(L1,F58);
- __ mov(L4,L0);
- __ mov(L5,L1);
- __ fxor(FloatRegisterImpl::D, F56, F60, F60);
- __ fxor(FloatRegisterImpl::D, F58, F62, F62);
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, G1);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_first_block);
- __ delayed()->edge8n(to, G0, G2);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F60, to, 0);
- __ stf(FloatRegisterImpl::D, F62, to, 8);
- __ ba_short(L_check_decrypt_end);
-
- __ BIND(L_store_misaligned_output_first_block);
- __ add(to, 8, G3);
- __ mov(8, G4);
- __ sub(G4, G1, G4);
- __ alignaddr(G4, G0, G4);
- __ faligndata(F60, F60, F60);
- __ faligndata(F62, F62, F62);
- __ mov(to, G1);
- __ and3(to, -8, to);
- __ and3(G3, -8, G3);
- __ stpartialf(to, G2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(G3, G2, F62, Assembler::ASI_PST8_PRIMARY);
- __ add(to, 8, to);
- __ add(G3, 8, G3);
- __ orn(G0, G2, G2);
- __ stpartialf(to, G2, F60, Assembler::ASI_PST8_PRIMARY);
- __ stpartialf(G3, G2, F62, Assembler::ASI_PST8_PRIMARY);
- __ mov(G1, to);
-
- __ BIND(L_check_decrypt_end);
- __ add(from, 16, from);
- __ add(to, 16, to);
- __ subcc(len_reg, 16, len_reg);
- __ br(Assembler::equal, false, Assembler::pt, L_cbcdec_end);
- __ delayed()->nop();
-
- // 256-bit original key size
- __ cmp_and_brx_short(keylen, 60, Assembler::equal, Assembler::pn, L_dec_next2_blocks256);
-
- // 192-bit original key size
- __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_dec_next2_blocks192);
-
- __ align(OptoLoopAlignment);
- __ BIND(L_dec_next2_blocks128);
- __ nop();
-
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_next2_blocks128);
- __ delayed()->mov(from, G1); // save original 'from' address before alignaddr
-
- // aligned case: load input into G4, G5, L4 and L5
- __ ldx(from,0,G4);
- __ ldx(from,8,G5);
- __ ldx(from,16,L4);
- __ ldx(from,24,L5);
- __ ba_short(L_transform_next2_blocks128);
-
- __ BIND(L_load_misaligned_next2_blocks128);
- __ alignaddr(from, G0, from);
- // F40, F42, F58, F60, F62 can be clobbered
- __ ldf(FloatRegisterImpl::D, from, 0, F40);
- __ ldf(FloatRegisterImpl::D, from, 8, F42);
- __ ldf(FloatRegisterImpl::D, from, 16, F60);
- __ ldf(FloatRegisterImpl::D, from, 24, F62);
- __ ldf(FloatRegisterImpl::D, from, 32, F58);
- __ faligndata(F40, F42, F40);
- __ faligndata(F42, F60, F42);
- __ faligndata(F60, F62, F60);
- __ faligndata(F62, F58, F62);
- __ movdtox(F40, G4);
- __ movdtox(F42, G5);
- __ movdtox(F60, L4);
- __ movdtox(F62, L5);
- __ mov(G1, from);
-
- __ BIND(L_transform_next2_blocks128);
- // F40:F42 used for first 16-bytes
- __ xor3(L2,G4,G1);
- __ movxtod(G1,F40);
- __ xor3(L3,G5,G1);
- __ movxtod(G1,F42);
-
- // F60:F62 used for next 16-bytes
- __ xor3(L2,L4,G1);
- __ movxtod(G1,F60);
- __ xor3(L3,L5,G1);
- __ movxtod(G1,F62);
-
- for ( int i = 38; i >= 6; i -= 8 ) {
- __ aes_dround23(as_FloatRegister(i), F40, F42, F44);
- __ aes_dround01(as_FloatRegister(i-2), F40, F42, F46);
- __ aes_dround23(as_FloatRegister(i), F60, F62, F58);
- __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56);
- if (i != 6 ) {
- __ aes_dround23(as_FloatRegister(i-4), F46, F44, F42);
- __ aes_dround01(as_FloatRegister(i-6), F46, F44, F40);
- __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62);
- __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60);
- } else {
- __ aes_dround23_l(as_FloatRegister(i-4), F46, F44, F42);
- __ aes_dround01_l(as_FloatRegister(i-6), F46, F44, F40);
- __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F62);
- __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F60);
- }
- }
-
- __ movxtod(L0,F46);
- __ movxtod(L1,F44);
- __ fxor(FloatRegisterImpl::D, F46, F40, F40);
- __ fxor(FloatRegisterImpl::D, F44, F42, F42);
-
- __ movxtod(G4,F56);
- __ movxtod(G5,F58);
- __ mov(L4,L0);
- __ mov(L5,L1);
- __ fxor(FloatRegisterImpl::D, F56, F60, F60);
- __ fxor(FloatRegisterImpl::D, F58, F62, F62);
-
- // For mis-aligned store of 32 bytes of result we can do:
- // Circular right-shift all 4 FP registers so that 'head' and 'tail'
- // parts that need to be stored starting at mis-aligned address are in a FP reg
- // the other 3 FP regs can thus be stored using regular store
- // we then use the edge + partial-store mechanism to store the 'head' and 'tail' parts
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, G1);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_next2_blocks128);
- __ delayed()->edge8n(to, G0, G2);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F40, to, 0);
- __ stf(FloatRegisterImpl::D, F42, to, 8);
- __ stf(FloatRegisterImpl::D, F60, to, 16);
- __ stf(FloatRegisterImpl::D, F62, to, 24);
- __ ba_short(L_check_decrypt_loop_end128);
-
- __ BIND(L_store_misaligned_output_next2_blocks128);
- __ mov(8, G4);
- __ sub(G4, G1, G4);
- __ alignaddr(G4, G0, G4);
- __ faligndata(F40, F42, F56); // F56 can be clobbered
- __ faligndata(F42, F60, F42);
- __ faligndata(F60, F62, F60);
- __ faligndata(F62, F40, F40);
- __ mov(to, G1);
- __ and3(to, -8, to);
- __ stpartialf(to, G2, F40, Assembler::ASI_PST8_PRIMARY);
- __ stf(FloatRegisterImpl::D, F56, to, 8);
- __ stf(FloatRegisterImpl::D, F42, to, 16);
- __ stf(FloatRegisterImpl::D, F60, to, 24);
- __ add(to, 32, to);
- __ orn(G0, G2, G2);
- __ stpartialf(to, G2, F40, Assembler::ASI_PST8_PRIMARY);
- __ mov(G1, to);
-
- __ BIND(L_check_decrypt_loop_end128);
- __ add(from, 32, from);
- __ add(to, 32, to);
- __ subcc(len_reg, 32, len_reg);
- __ br(Assembler::notEqual, false, Assembler::pt, L_dec_next2_blocks128);
- __ delayed()->nop();
- __ ba_short(L_cbcdec_end);
-
- __ align(OptoLoopAlignment);
- __ BIND(L_dec_next2_blocks192);
- __ nop();
-
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_next2_blocks192);
- __ delayed()->mov(from, G1); // save original 'from' address before alignaddr
-
- // aligned case: load input into G4, G5, L4 and L5
- __ ldx(from,0,G4);
- __ ldx(from,8,G5);
- __ ldx(from,16,L4);
- __ ldx(from,24,L5);
- __ ba_short(L_transform_next2_blocks192);
-
- __ BIND(L_load_misaligned_next2_blocks192);
- __ alignaddr(from, G0, from);
- // F48, F50, F52, F60, F62 can be clobbered
- __ ldf(FloatRegisterImpl::D, from, 0, F48);
- __ ldf(FloatRegisterImpl::D, from, 8, F50);
- __ ldf(FloatRegisterImpl::D, from, 16, F60);
- __ ldf(FloatRegisterImpl::D, from, 24, F62);
- __ ldf(FloatRegisterImpl::D, from, 32, F52);
- __ faligndata(F48, F50, F48);
- __ faligndata(F50, F60, F50);
- __ faligndata(F60, F62, F60);
- __ faligndata(F62, F52, F62);
- __ movdtox(F48, G4);
- __ movdtox(F50, G5);
- __ movdtox(F60, L4);
- __ movdtox(F62, L5);
- __ mov(G1, from);
-
- __ BIND(L_transform_next2_blocks192);
- // F48:F50 used for first 16-bytes
- __ xor3(L2,G4,G1);
- __ movxtod(G1,F48);
- __ xor3(L3,G5,G1);
- __ movxtod(G1,F50);
-
- // F60:F62 used for next 16-bytes
- __ xor3(L2,L4,G1);
- __ movxtod(G1,F60);
- __ xor3(L3,L5,G1);
- __ movxtod(G1,F62);
-
- for ( int i = 46; i >= 6; i -= 8 ) {
- __ aes_dround23(as_FloatRegister(i), F48, F50, F52);
- __ aes_dround01(as_FloatRegister(i-2), F48, F50, F54);
- __ aes_dround23(as_FloatRegister(i), F60, F62, F58);
- __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56);
- if (i != 6 ) {
- __ aes_dround23(as_FloatRegister(i-4), F54, F52, F50);
- __ aes_dround01(as_FloatRegister(i-6), F54, F52, F48);
- __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62);
- __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60);
- } else {
- __ aes_dround23_l(as_FloatRegister(i-4), F54, F52, F50);
- __ aes_dround01_l(as_FloatRegister(i-6), F54, F52, F48);
- __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F62);
- __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F60);
- }
- }
-
- __ movxtod(L0,F54);
- __ movxtod(L1,F52);
- __ fxor(FloatRegisterImpl::D, F54, F48, F48);
- __ fxor(FloatRegisterImpl::D, F52, F50, F50);
-
- __ movxtod(G4,F56);
- __ movxtod(G5,F58);
- __ mov(L4,L0);
- __ mov(L5,L1);
- __ fxor(FloatRegisterImpl::D, F56, F60, F60);
- __ fxor(FloatRegisterImpl::D, F58, F62, F62);
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, G1);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_next2_blocks192);
- __ delayed()->edge8n(to, G0, G2);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F48, to, 0);
- __ stf(FloatRegisterImpl::D, F50, to, 8);
- __ stf(FloatRegisterImpl::D, F60, to, 16);
- __ stf(FloatRegisterImpl::D, F62, to, 24);
- __ ba_short(L_check_decrypt_loop_end192);
-
- __ BIND(L_store_misaligned_output_next2_blocks192);
- __ mov(8, G4);
- __ sub(G4, G1, G4);
- __ alignaddr(G4, G0, G4);
- __ faligndata(F48, F50, F56); // F56 can be clobbered
- __ faligndata(F50, F60, F50);
- __ faligndata(F60, F62, F60);
- __ faligndata(F62, F48, F48);
- __ mov(to, G1);
- __ and3(to, -8, to);
- __ stpartialf(to, G2, F48, Assembler::ASI_PST8_PRIMARY);
- __ stf(FloatRegisterImpl::D, F56, to, 8);
- __ stf(FloatRegisterImpl::D, F50, to, 16);
- __ stf(FloatRegisterImpl::D, F60, to, 24);
- __ add(to, 32, to);
- __ orn(G0, G2, G2);
- __ stpartialf(to, G2, F48, Assembler::ASI_PST8_PRIMARY);
- __ mov(G1, to);
-
- __ BIND(L_check_decrypt_loop_end192);
- __ add(from, 32, from);
- __ add(to, 32, to);
- __ subcc(len_reg, 32, len_reg);
- __ br(Assembler::notEqual, false, Assembler::pt, L_dec_next2_blocks192);
- __ delayed()->nop();
- __ ba_short(L_cbcdec_end);
-
- __ align(OptoLoopAlignment);
- __ BIND(L_dec_next2_blocks256);
- __ nop();
-
- // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero
- __ andcc(from, 7, G0);
- __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_next2_blocks256);
- __ delayed()->mov(from, G1); // save original 'from' address before alignaddr
-
- // aligned case: load input into G4, G5, L4 and L5
- __ ldx(from,0,G4);
- __ ldx(from,8,G5);
- __ ldx(from,16,L4);
- __ ldx(from,24,L5);
- __ ba_short(L_transform_next2_blocks256);
-
- __ BIND(L_load_misaligned_next2_blocks256);
- __ alignaddr(from, G0, from);
- // F0, F2, F4, F60, F62 can be clobbered
- __ ldf(FloatRegisterImpl::D, from, 0, F0);
- __ ldf(FloatRegisterImpl::D, from, 8, F2);
- __ ldf(FloatRegisterImpl::D, from, 16, F60);
- __ ldf(FloatRegisterImpl::D, from, 24, F62);
- __ ldf(FloatRegisterImpl::D, from, 32, F4);
- __ faligndata(F0, F2, F0);
- __ faligndata(F2, F60, F2);
- __ faligndata(F60, F62, F60);
- __ faligndata(F62, F4, F62);
- __ movdtox(F0, G4);
- __ movdtox(F2, G5);
- __ movdtox(F60, L4);
- __ movdtox(F62, L5);
- __ mov(G1, from);
-
- __ BIND(L_transform_next2_blocks256);
- // F0:F2 used for first 16-bytes
- __ xor3(L2,G4,G1);
- __ movxtod(G1,F0);
- __ xor3(L3,G5,G1);
- __ movxtod(G1,F2);
-
- // F60:F62 used for next 16-bytes
- __ xor3(L2,L4,G1);
- __ movxtod(G1,F60);
- __ xor3(L3,L5,G1);
- __ movxtod(G1,F62);
-
- __ aes_dround23(F54, F0, F2, F4);
- __ aes_dround01(F52, F0, F2, F6);
- __ aes_dround23(F54, F60, F62, F58);
- __ aes_dround01(F52, F60, F62, F56);
- __ aes_dround23(F50, F6, F4, F2);
- __ aes_dround01(F48, F6, F4, F0);
- __ aes_dround23(F50, F56, F58, F62);
- __ aes_dround01(F48, F56, F58, F60);
- // save F48:F54 in temp registers
- __ movdtox(F54,G2);
- __ movdtox(F52,G3);
- __ movdtox(F50,L6);
- __ movdtox(F48,G1);
- for ( int i = 46; i >= 14; i -= 8 ) {
- __ aes_dround23(as_FloatRegister(i), F0, F2, F4);
- __ aes_dround01(as_FloatRegister(i-2), F0, F2, F6);
- __ aes_dround23(as_FloatRegister(i), F60, F62, F58);
- __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56);
- __ aes_dround23(as_FloatRegister(i-4), F6, F4, F2);
- __ aes_dround01(as_FloatRegister(i-6), F6, F4, F0);
- __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62);
- __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60);
- }
- // init F48:F54 with F0:F6 values (original key)
- __ ldf(FloatRegisterImpl::D, original_key, 0, F48);
- __ ldf(FloatRegisterImpl::D, original_key, 8, F50);
- __ ldf(FloatRegisterImpl::D, original_key, 16, F52);
- __ ldf(FloatRegisterImpl::D, original_key, 24, F54);
- __ aes_dround23(F54, F0, F2, F4);
- __ aes_dround01(F52, F0, F2, F6);
- __ aes_dround23(F54, F60, F62, F58);
- __ aes_dround01(F52, F60, F62, F56);
- __ aes_dround23_l(F50, F6, F4, F2);
- __ aes_dround01_l(F48, F6, F4, F0);
- __ aes_dround23_l(F50, F56, F58, F62);
- __ aes_dround01_l(F48, F56, F58, F60);
- // re-init F48:F54 with their original values
- __ movxtod(G2,F54);
- __ movxtod(G3,F52);
- __ movxtod(L6,F50);
- __ movxtod(G1,F48);
-
- __ movxtod(L0,F6);
- __ movxtod(L1,F4);
- __ fxor(FloatRegisterImpl::D, F6, F0, F0);
- __ fxor(FloatRegisterImpl::D, F4, F2, F2);
-
- __ movxtod(G4,F56);
- __ movxtod(G5,F58);
- __ mov(L4,L0);
- __ mov(L5,L1);
- __ fxor(FloatRegisterImpl::D, F56, F60, F60);
- __ fxor(FloatRegisterImpl::D, F58, F62, F62);
-
- // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero
- __ andcc(to, 7, G1);
- __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_next2_blocks256);
- __ delayed()->edge8n(to, G0, G2);
-
- // aligned case: store output into the destination array
- __ stf(FloatRegisterImpl::D, F0, to, 0);
- __ stf(FloatRegisterImpl::D, F2, to, 8);
- __ stf(FloatRegisterImpl::D, F60, to, 16);
- __ stf(FloatRegisterImpl::D, F62, to, 24);
- __ ba_short(L_check_decrypt_loop_end256);
-
- __ BIND(L_store_misaligned_output_next2_blocks256);
- __ mov(8, G4);
- __ sub(G4, G1, G4);
- __ alignaddr(G4, G0, G4);
- __ faligndata(F0, F2, F56); // F56 can be clobbered
- __ faligndata(F2, F60, F2);
- __ faligndata(F60, F62, F60);
- __ faligndata(F62, F0, F0);
- __ mov(to, G1);
- __ and3(to, -8, to);
- __ stpartialf(to, G2, F0, Assembler::ASI_PST8_PRIMARY);
- __ stf(FloatRegisterImpl::D, F56, to, 8);
- __ stf(FloatRegisterImpl::D, F2, to, 16);
- __ stf(FloatRegisterImpl::D, F60, to, 24);
- __ add(to, 32, to);
- __ orn(G0, G2, G2);
- __ stpartialf(to, G2, F0, Assembler::ASI_PST8_PRIMARY);
- __ mov(G1, to);
-
- __ BIND(L_check_decrypt_loop_end256);
- __ add(from, 32, from);
- __ add(to, 32, to);
- __ subcc(len_reg, 32, len_reg);
- __ br(Assembler::notEqual, false, Assembler::pt, L_dec_next2_blocks256);
- __ delayed()->nop();
-
- __ BIND(L_cbcdec_end);
- // re-init intial vector for next block, 8-byte alignment is guaranteed
- __ stx(L0, rvec, 0);
- __ stx(L1, rvec, 8);
- __ mov(L7, I0);
- __ ret();
- __ delayed()->restore();
-
- return start;
- }
-
- address generate_sha1_implCompress(bool multi_block, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- Label L_sha1_loop, L_sha1_unaligned_input, L_sha1_unaligned_input_loop;
- int i;
-
- Register buf = O0; // byte[] source+offset
- Register state = O1; // int[] SHA.state
- Register ofs = O2; // int offset
- Register limit = O3; // int limit
-
- // load state into F0-F4
- for (i = 0; i < 5; i++) {
- __ ldf(FloatRegisterImpl::S, state, i*4, as_FloatRegister(i));
- }
-
- __ andcc(buf, 7, G0);
- __ br(Assembler::notZero, false, Assembler::pn, L_sha1_unaligned_input);
- __ delayed()->nop();
-
- __ BIND(L_sha1_loop);
- // load buf into F8-F22
- for (i = 0; i < 8; i++) {
- __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8));
- }
- __ sha1();
- if (multi_block) {
- __ add(ofs, 64, ofs);
- __ add(buf, 64, buf);
- __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha1_loop);
- __ mov(ofs, O0); // to be returned
- }
-
- // store F0-F4 into state and return
- for (i = 0; i < 4; i++) {
- __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4);
- }
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::S, F4, state, 0x10);
-
- __ BIND(L_sha1_unaligned_input);
- __ alignaddr(buf, G0, buf);
-
- __ BIND(L_sha1_unaligned_input_loop);
- // load buf into F8-F22
- for (i = 0; i < 9; i++) {
- __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8));
- }
- for (i = 0; i < 8; i++) {
- __ faligndata(as_FloatRegister(i*2 + 8), as_FloatRegister(i*2 + 10), as_FloatRegister(i*2 + 8));
- }
- __ sha1();
- if (multi_block) {
- __ add(ofs, 64, ofs);
- __ add(buf, 64, buf);
- __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha1_unaligned_input_loop);
- __ mov(ofs, O0); // to be returned
- }
-
- // store F0-F4 into state and return
- for (i = 0; i < 4; i++) {
- __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4);
- }
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::S, F4, state, 0x10);
-
- return start;
- }
-
- address generate_sha256_implCompress(bool multi_block, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- Label L_sha256_loop, L_sha256_unaligned_input, L_sha256_unaligned_input_loop;
- int i;
-
- Register buf = O0; // byte[] source+offset
- Register state = O1; // int[] SHA2.state
- Register ofs = O2; // int offset
- Register limit = O3; // int limit
-
- // load state into F0-F7
- for (i = 0; i < 8; i++) {
- __ ldf(FloatRegisterImpl::S, state, i*4, as_FloatRegister(i));
- }
-
- __ andcc(buf, 7, G0);
- __ br(Assembler::notZero, false, Assembler::pn, L_sha256_unaligned_input);
- __ delayed()->nop();
-
- __ BIND(L_sha256_loop);
- // load buf into F8-F22
- for (i = 0; i < 8; i++) {
- __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8));
- }
- __ sha256();
- if (multi_block) {
- __ add(ofs, 64, ofs);
- __ add(buf, 64, buf);
- __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha256_loop);
- __ mov(ofs, O0); // to be returned
- }
-
- // store F0-F7 into state and return
- for (i = 0; i < 7; i++) {
- __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4);
- }
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::S, F7, state, 0x1c);
-
- __ BIND(L_sha256_unaligned_input);
- __ alignaddr(buf, G0, buf);
-
- __ BIND(L_sha256_unaligned_input_loop);
- // load buf into F8-F22
- for (i = 0; i < 9; i++) {
- __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8));
- }
- for (i = 0; i < 8; i++) {
- __ faligndata(as_FloatRegister(i*2 + 8), as_FloatRegister(i*2 + 10), as_FloatRegister(i*2 + 8));
- }
- __ sha256();
- if (multi_block) {
- __ add(ofs, 64, ofs);
- __ add(buf, 64, buf);
- __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha256_unaligned_input_loop);
- __ mov(ofs, O0); // to be returned
- }
-
- // store F0-F7 into state and return
- for (i = 0; i < 7; i++) {
- __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4);
- }
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::S, F7, state, 0x1c);
-
- return start;
- }
-
- address generate_sha512_implCompress(bool multi_block, const char *name) {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", name);
- address start = __ pc();
-
- Label L_sha512_loop, L_sha512_unaligned_input, L_sha512_unaligned_input_loop;
- int i;
-
- Register buf = O0; // byte[] source+offset
- Register state = O1; // long[] SHA5.state
- Register ofs = O2; // int offset
- Register limit = O3; // int limit
-
- // load state into F0-F14
- for (i = 0; i < 8; i++) {
- __ ldf(FloatRegisterImpl::D, state, i*8, as_FloatRegister(i*2));
- }
-
- __ andcc(buf, 7, G0);
- __ br(Assembler::notZero, false, Assembler::pn, L_sha512_unaligned_input);
- __ delayed()->nop();
-
- __ BIND(L_sha512_loop);
- // load buf into F16-F46
- for (i = 0; i < 16; i++) {
- __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 16));
- }
- __ sha512();
- if (multi_block) {
- __ add(ofs, 128, ofs);
- __ add(buf, 128, buf);
- __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha512_loop);
- __ mov(ofs, O0); // to be returned
- }
-
- // store F0-F14 into state and return
- for (i = 0; i < 7; i++) {
- __ stf(FloatRegisterImpl::D, as_FloatRegister(i*2), state, i*8);
- }
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::D, F14, state, 0x38);
-
- __ BIND(L_sha512_unaligned_input);
- __ alignaddr(buf, G0, buf);
-
- __ BIND(L_sha512_unaligned_input_loop);
- // load buf into F16-F46
- for (i = 0; i < 17; i++) {
- __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 16));
- }
- for (i = 0; i < 16; i++) {
- __ faligndata(as_FloatRegister(i*2 + 16), as_FloatRegister(i*2 + 18), as_FloatRegister(i*2 + 16));
- }
- __ sha512();
- if (multi_block) {
- __ add(ofs, 128, ofs);
- __ add(buf, 128, buf);
- __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha512_unaligned_input_loop);
- __ mov(ofs, O0); // to be returned
- }
-
- // store F0-F14 into state and return
- for (i = 0; i < 7; i++) {
- __ stf(FloatRegisterImpl::D, as_FloatRegister(i*2), state, i*8);
- }
- __ retl();
- __ delayed()->stf(FloatRegisterImpl::D, F14, state, 0x38);
-
- return start;
- }
-
- /* Single and multi-block ghash operations */
- address generate_ghash_processBlocks() {
- __ align(CodeEntryAlignment);
- Label L_ghash_loop, L_aligned, L_main;
- StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks");
- address start = __ pc();
-
- Register state = I0;
- Register subkeyH = I1;
- Register data = I2;
- Register len = I3;
-
- __ save_frame(0);
-
- __ ldx(state, 0, O0);
- __ ldx(state, 8, O1);
-
- // Loop label for multiblock operations
- __ BIND(L_ghash_loop);
-
- // Check if 'data' is unaligned
- __ andcc(data, 7, G1);
- __ br(Assembler::zero, false, Assembler::pt, L_aligned);
- __ delayed()->nop();
-
- Register left_shift = L1;
- Register right_shift = L2;
- Register data_ptr = L3;
-
- // Get left and right shift values in bits
- __ sll(G1, LogBitsPerByte, left_shift);
- __ mov(64, right_shift);
- __ sub(right_shift, left_shift, right_shift);
-
- // Align to read 'data'
- __ sub(data, G1, data_ptr);
-
- // Load first 8 bytes of 'data'
- __ ldx(data_ptr, 0, O4);
- __ sllx(O4, left_shift, O4);
- __ ldx(data_ptr, 8, O5);
- __ srlx(O5, right_shift, G4);
- __ bset(G4, O4);
-
- // Load second 8 bytes of 'data'
- __ sllx(O5, left_shift, O5);
- __ ldx(data_ptr, 16, G4);
- __ srlx(G4, right_shift, G4);
- __ ba(L_main);
- __ delayed()->bset(G4, O5);
-
- // If 'data' is aligned, load normally
- __ BIND(L_aligned);
- __ ldx(data, 0, O4);
- __ ldx(data, 8, O5);
-
- __ BIND(L_main);
- __ ldx(subkeyH, 0, O2);
- __ ldx(subkeyH, 8, O3);
-
- __ xor3(O0, O4, O0);
- __ xor3(O1, O5, O1);
-
- __ xmulxhi(O0, O3, G3);
- __ xmulx(O0, O2, O5);
- __ xmulxhi(O1, O2, G4);
- __ xmulxhi(O1, O3, G5);
- __ xmulx(O0, O3, G1);
- __ xmulx(O1, O3, G2);
- __ xmulx(O1, O2, O3);
- __ xmulxhi(O0, O2, O4);
-
- __ mov(0xE1, O0);
- __ sllx(O0, 56, O0);
-
- __ xor3(O5, G3, O5);
- __ xor3(O5, G4, O5);
- __ xor3(G5, G1, G1);
- __ xor3(G1, O3, G1);
- __ srlx(G2, 63, O1);
- __ srlx(G1, 63, G3);
- __ sllx(G2, 63, O3);
- __ sllx(G2, 58, O2);
- __ xor3(O3, O2, O2);
-
- __ sllx(G1, 1, G1);
- __ or3(G1, O1, G1);
-
- __ xor3(G1, O2, G1);
-
- __ sllx(G2, 1, G2);
-
- __ xmulxhi(G1, O0, O1);
- __ xmulx(G1, O0, O2);
- __ xmulxhi(G2, O0, O3);
- __ xmulx(G2, O0, G1);
-
- __ xor3(O4, O1, O4);
- __ xor3(O5, O2, O5);
- __ xor3(O5, O3, O5);
-
- __ sllx(O4, 1, O2);
- __ srlx(O5, 63, O3);
-
- __ or3(O2, O3, O0);
-
- __ sllx(O5, 1, O1);
- __ srlx(G1, 63, O2);
- __ or3(O1, O2, O1);
- __ xor3(O1, G3, O1);
-
- __ deccc(len);
- __ br(Assembler::notZero, true, Assembler::pt, L_ghash_loop);
- __ delayed()->add(data, 16, data);
-
- __ stx(O0, I0, 0);
- __ stx(O1, I0, 8);
-
- __ ret();
- __ delayed()->restore();
-
- return start;
- }
-
- /**
- * Arguments:
- *
- * Inputs:
- * O0 - int crc
- * O1 - byte* buf
- * O2 - int len
- * O3 - int* table
- *
- * Output:
- * O0 - int crc result
- */
- address generate_updateBytesCRC32C() {
- assert(UseCRC32CIntrinsics, "need CRC32C instruction");
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C");
- address start = __ pc();
-
- const Register crc = O0; // crc
- const Register buf = O1; // source java byte array address
- const Register len = O2; // number of bytes
- const Register table = O3; // byteTable
-
- __ kernel_crc32c(crc, buf, len, table);
-
- __ retl();
- __ delayed()->nop();
-
- return start;
- }
-
-#define ADLER32_NUM_TEMPS 16
-
- /**
- * Arguments:
- *
- * Inputs:
- * O0 - int adler
- * O1 - byte* buff
- * O2 - int len
- *
- * Output:
- * O0 - int adler result
- */
- address generate_updateBytesAdler32() {
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "updateBytesAdler32");
- address start = __ pc();
-
- Label L_cleanup_loop, L_cleanup_loop_check;
- Label L_main_loop_check, L_main_loop, L_inner_loop, L_inner_loop_check;
- Label L_nmax_check_done;
-
- // Aliases
- Register s1 = O0;
- Register s2 = O3;
- Register buff = O1;
- Register len = O2;
- Register temp[ADLER32_NUM_TEMPS] = {L0, L1, L2, L3, L4, L5, L6, L7, I0, I1, I2, I3, I4, I5, G3, I7};
-
- // Max number of bytes we can process before having to take the mod
- // 0x15B0 is 5552 in decimal, the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
- unsigned long NMAX = 0x15B0;
-
- // Zero-out the upper bits of len
- __ clruwu(len);
-
- // Create the mask 0xFFFF
- __ set64(0x00FFFF, O4, O5); // O5 is the temp register
-
- // s1 is initialized to the lower 16 bits of adler
- // s2 is initialized to the upper 16 bits of adler
- __ srlx(O0, 16, O5); // adler >> 16
- __ and3(O0, O4, s1); // s1 = (adler & 0xFFFF)
- __ and3(O5, O4, s2); // s2 = ((adler >> 16) & 0xFFFF)
-
- // The pipelined loop needs at least 16 elements for 1 iteration
- // It does check this, but it is more effective to skip to the cleanup loop
- // Setup the constant for cutoff checking
- __ mov(15, O4);
-
- // Check if we are above the cutoff, if not go to the cleanup loop immediately
- __ cmp_and_br_short(len, O4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_loop_check);
-
- // Free up some registers for our use
- for (int i = 0; i < ADLER32_NUM_TEMPS; i++) {
- __ movxtod(temp[i], as_FloatRegister(2*i));
- }
-
- // Loop maintenance stuff is done at the end of the loop, so skip to there
- __ ba_short(L_main_loop_check);
-
- __ BIND(L_main_loop);
-
- // Prologue for inner loop
- __ ldub(buff, 0, L0);
- __ dec(O5);
-
- for (int i = 1; i < 8; i++) {
- __ ldub(buff, i, temp[i]);
- }
-
- __ inc(buff, 8);
-
- // Inner loop processes 16 elements at a time, might never execute if only 16 elements
- // to be processed by the outter loop
- __ ba_short(L_inner_loop_check);
-
- __ BIND(L_inner_loop);
-
- for (int i = 0; i < 8; i++) {
- __ ldub(buff, (2*i), temp[(8+(2*i)) % ADLER32_NUM_TEMPS]);
- __ add(s1, temp[i], s1);
- __ ldub(buff, (2*i)+1, temp[(8+(2*i)+1) % ADLER32_NUM_TEMPS]);
- __ add(s2, s1, s2);
- }
-
- // Original temp 0-7 used and new loads to temp 0-7 issued
- // temp 8-15 ready to be consumed
- __ add(s1, I0, s1);
- __ dec(O5);
- __ add(s2, s1, s2);
- __ add(s1, I1, s1);
- __ inc(buff, 16);
- __ add(s2, s1, s2);
-
- for (int i = 0; i < 6; i++) {
- __ add(s1, temp[10+i], s1);
- __ add(s2, s1, s2);
- }
-
- __ BIND(L_inner_loop_check);
- __ nop();
- __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pt, L_inner_loop);
-
- // Epilogue
- for (int i = 0; i < 4; i++) {
- __ ldub(buff, (2*i), temp[8+(2*i)]);
- __ add(s1, temp[i], s1);
- __ ldub(buff, (2*i)+1, temp[8+(2*i)+1]);
- __ add(s2, s1, s2);
- }
-
- __ add(s1, temp[4], s1);
- __ inc(buff, 8);
-
- for (int i = 0; i < 11; i++) {
- __ add(s2, s1, s2);
- __ add(s1, temp[5+i], s1);
- }
-
- __ add(s2, s1, s2);
-
- // Take the mod for s1 and s2
- __ set64(0xFFF1, L0, L1);
- __ udivx(s1, L0, L1);
- __ udivx(s2, L0, L2);
- __ mulx(L0, L1, L1);
- __ mulx(L0, L2, L2);
- __ sub(s1, L1, s1);
- __ sub(s2, L2, s2);
-
- // Make sure there is something left to process
- __ BIND(L_main_loop_check);
- __ set64(NMAX, L0, L1);
- // k = len < NMAX ? len : NMAX
- __ cmp_and_br_short(len, L0, Assembler::greaterEqualUnsigned, Assembler::pt, L_nmax_check_done);
- __ andn(len, 0x0F, L0); // only loop a multiple of 16 times
- __ BIND(L_nmax_check_done);
- __ mov(L0, O5);
- __ sub(len, L0, len); // len -= k
-
- __ srlx(O5, 4, O5); // multiplies of 16
- __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pt, L_main_loop);
-
- // Restore anything we used, take the mod one last time, combine and return
- // Restore any registers we saved
- for (int i = 0; i < ADLER32_NUM_TEMPS; i++) {
- __ movdtox(as_FloatRegister(2*i), temp[i]);
- }
-
- // There might be nothing left to process
- __ ba_short(L_cleanup_loop_check);
-
- __ BIND(L_cleanup_loop);
- __ ldub(buff, 0, O4); // load single byte form buffer
- __ inc(buff); // buff++
- __ add(s1, O4, s1); // s1 += *buff++;
- __ dec(len); // len--
- __ add(s1, s2, s2); // s2 += s1;
- __ BIND(L_cleanup_loop_check);
- __ nop();
- __ cmp_and_br_short(len, 0, Assembler::notEqual, Assembler::pt, L_cleanup_loop);
-
- // Take the mod one last time
- __ set64(0xFFF1, O1, O2);
- __ udivx(s1, O1, O2);
- __ udivx(s2, O1, O5);
- __ mulx(O1, O2, O2);
- __ mulx(O1, O5, O5);
- __ sub(s1, O2, s1);
- __ sub(s2, O5, s2);
-
- // Combine lower bits and higher bits
- __ sllx(s2, 16, s2); // s2 = s2 << 16
- __ or3(s1, s2, s1); // adler = s2 | s1
- // Final return value is in O0
- __ retl();
- __ delayed()->nop();
-
- return start;
- }
-
- /**
- * Arguments:
- *
- * Inputs:
- * O0 - int crc
- * O1 - byte* buf
- * O2 - int len
- * O3 - int* table
- *
- * Output:
- * O0 - int crc result
- */
- address generate_updateBytesCRC32() {
- assert(UseCRC32Intrinsics, "need VIS3 instructions");
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32");
- address start = __ pc();
-
- const Register crc = O0; // crc
- const Register buf = O1; // source java byte array address
- const Register len = O2; // length
- const Register table = O3; // crc_table address (reuse register)
-
- __ kernel_crc32(crc, buf, len, table);
-
- __ retl();
- __ delayed()->nop();
-
- return start;
- }
-
- /**
- * Arguments:
- *
- * Inputs:
- * I0 - int* x-addr
- * I1 - int x-len
- * I2 - int* y-addr
- * I3 - int y-len
- * I4 - int* z-addr (output vector)
- * I5 - int z-len
- */
- address generate_multiplyToLen() {
- assert(UseMultiplyToLenIntrinsic, "need VIS3 instructions");
-
- __ align(CodeEntryAlignment);
- StubCodeMark mark(this, "StubRoutines", "multiplyToLen");
- address start = __ pc();
-
- __ save_frame(0);
-
- const Register xptr = I0; // input address
- const Register xlen = I1; // ...and length in 32b-words
- const Register yptr = I2; //
- const Register ylen = I3; //
- const Register zptr = I4; // output address
- const Register zlen = I5; // ...and length in 32b-words
-
- /* The minimal "limb" representation suggest that odd length vectors are as
- * likely as even length dittos. This in turn suggests that we need to cope
- * with odd/even length arrays and data not aligned properly for 64-bit read
- * and write operations. We thus use a number of different kernels:
- *
- * if (is_even(x.len) && is_even(y.len))
- * if (is_align64(x) && is_align64(y) && is_align64(z))
- * if (x.len == y.len && 16 <= x.len && x.len <= 64)
- * memv_mult_mpmul(...)
- * else
- * memv_mult_64x64(...)
- * else
- * memv_mult_64x64u(...)
- * else
- * memv_mult_32x32(...)
- *
- * Here we assume VIS3 support (for 'umulxhi', 'addxc' and 'addxccc').
- * In case CBCOND instructions are supported, we will use 'cxbX'. If the
- * MPMUL instruction is supported, we will generate a kernel using 'mpmul'
- * (for vectors with proper characteristics).
- */
- const Register tmp0 = L0;
- const Register tmp1 = L1;
-
- Label L_mult_32x32;
- Label L_mult_64x64u;
- Label L_mult_64x64;
- Label L_exit;
-
- if_both_even(xlen, ylen, tmp0, false, L_mult_32x32);
- if_all3_aligned(xptr, yptr, zptr, tmp1, 64, false, L_mult_64x64u);
-
- if (UseMPMUL) {
- if_eq(xlen, ylen, false, L_mult_64x64);
- if_in_rng(xlen, 16, 64, tmp0, tmp1, false, L_mult_64x64);
-
- // 1. Multiply naturally aligned 64b-datums using a generic 'mpmul' kernel,
- // operating on equal length vectors of size [16..64].
- gen_mult_mpmul(xlen, xptr, yptr, zptr, L_exit);
- }
-
- // 2. Multiply naturally aligned 64-bit datums (64x64).
- __ bind(L_mult_64x64);
- gen_mult_64x64(xptr, xlen, yptr, ylen, zptr, zlen, L_exit);
-
- // 3. Multiply unaligned 64-bit datums (64x64).
- __ bind(L_mult_64x64u);
- gen_mult_64x64_unaligned(xptr, xlen, yptr, ylen, zptr, zlen, L_exit);
-
- // 4. Multiply naturally aligned 32-bit datums (32x32).
- __ bind(L_mult_32x32);
- gen_mult_32x32(xptr, xlen, yptr, ylen, zptr, zlen, L_exit);
-
- __ bind(L_exit);
- __ ret();
- __ delayed()->restore();
-
- return start;
- }
-
- // Additional help functions used by multiplyToLen generation.
-
- void if_both_even(Register r1, Register r2, Register tmp, bool iseven, Label &L)
- {
- __ or3(r1, r2, tmp);
- __ andcc(tmp, 0x1, tmp);
- __ br_icc_zero(iseven, Assembler::pn, L);
- }
-
- void if_all3_aligned(Register r1, Register r2, Register r3,
- Register tmp, uint align, bool isalign, Label &L)
- {
- __ or3(r1, r2, tmp);
- __ or3(r3, tmp, tmp);
- __ andcc(tmp, (align - 1), tmp);
- __ br_icc_zero(isalign, Assembler::pn, L);
- }
-
- void if_eq(Register x, Register y, bool iseq, Label &L)
- {
- Assembler::Condition cf = (iseq ? Assembler::equal : Assembler::notEqual);
- __ cmp_and_br_short(x, y, cf, Assembler::pt, L);
- }
-
- void if_in_rng(Register x, int lb, int ub, Register t1, Register t2, bool inrng, Label &L)
- {
- assert(Assembler::is_simm13(lb), "Small ints only!");
- assert(Assembler::is_simm13(ub), "Small ints only!");
- // Compute (x - lb) * (ub - x) >= 0
- // NOTE: With the local use of this routine, we rely on small integers to
- // guarantee that we do not overflow in the multiplication.
- __ add(G0, ub, t2);
- __ sub(x, lb, t1);
- __ sub(t2, x, t2);
- __ mulx(t1, t2, t1);
- Assembler::Condition cf = (inrng ? Assembler::greaterEqual : Assembler::less);
- __ cmp_and_br_short(t1, G0, cf, Assembler::pt, L);
- }
-
- void ldd_entry(Register base, Register offs, FloatRegister dest)
- {
- __ ldd(base, offs, dest);
- __ inc(offs, 8);
- }
-
- void ldx_entry(Register base, Register offs, Register dest)
- {
- __ ldx(base, offs, dest);
- __ inc(offs, 8);
- }
-
- void mpmul_entry(int m, Label &next)
- {
- __ mpmul(m);
- __ cbcond(Assembler::equal, Assembler::icc, G0, G0, next);
- }
-
- void stx_entry(Label &L, Register r1, Register r2, Register base, Register offs)
- {
- __ bind(L);
- __ stx(r1, base, offs);
- __ inc(offs, 8);
- __ stx(r2, base, offs);
- __ inc(offs, 8);
- }
-
- void offs_entry(Label &Lbl0, Label &Lbl1)
- {
- assert(Lbl0.is_bound(), "must be");
- assert(Lbl1.is_bound(), "must be");
-
- int offset = Lbl0.loc_pos() - Lbl1.loc_pos();
-
- __ emit_data(offset);
- }
-
- /* Generate the actual multiplication kernels for BigInteger vectors:
- *
- * 1. gen_mult_mpmul(...)
- *
- * 2. gen_mult_64x64(...)
- *
- * 3. gen_mult_64x64_unaligned(...)
- *
- * 4. gen_mult_32x32(...)
- */
- void gen_mult_mpmul(Register len, Register xptr, Register yptr, Register zptr,
- Label &L_exit)
- {
- const Register zero = G0;
- const Register gxp = G1; // Need to use global registers across RWs.
- const Register gyp = G2;
- const Register gzp = G3;
- const Register disp = G4;
- const Register offs = G5;
-
- __ mov(xptr, gxp);
- __ mov(yptr, gyp);
- __ mov(zptr, gzp);
-
- /* Compute jump vector entry:
- *
- * 1. mpmul input size (0..31) x 64b
- * 2. vector input size in 32b limbs (even number)
- * 3. branch entries in reverse order (31..0), using two
- * instructions per entry (2 * 4 bytes).
- *
- * displacement = byte_offset(bra_offset(len))
- * = byte_offset((64 - len)/2)
- * = 8 * (64 - len)/2
- * = 4 * (64 - len)
- */
- Register temp = I5; // Alright to use input regs. in first batch.
-
- __ sub(zero, len, temp);
- __ add(temp, 64, temp);
- __ sllx(temp, 2, disp); // disp := (64 - len) << 2
-
- // Dispatch relative current PC, into instruction table below.
- __ rdpc(temp);
- __ add(temp, 16, temp);
- __ jmp(temp, disp);
- __ delayed()->clr(offs);
-
- ldd_entry(gxp, offs, F22);
- ldd_entry(gxp, offs, F20);
- ldd_entry(gxp, offs, F18);
- ldd_entry(gxp, offs, F16);
- ldd_entry(gxp, offs, F14);
- ldd_entry(gxp, offs, F12);
- ldd_entry(gxp, offs, F10);
- ldd_entry(gxp, offs, F8);
- ldd_entry(gxp, offs, F6);
- ldd_entry(gxp, offs, F4);
- ldx_entry(gxp, offs, I5);
- ldx_entry(gxp, offs, I4);
- ldx_entry(gxp, offs, I3);
- ldx_entry(gxp, offs, I2);
- ldx_entry(gxp, offs, I1);
- ldx_entry(gxp, offs, I0);
- ldx_entry(gxp, offs, L7);
- ldx_entry(gxp, offs, L6);
- ldx_entry(gxp, offs, L5);
- ldx_entry(gxp, offs, L4);
- ldx_entry(gxp, offs, L3);
- ldx_entry(gxp, offs, L2);
- ldx_entry(gxp, offs, L1);
- ldx_entry(gxp, offs, L0);
- ldd_entry(gxp, offs, F2);
- ldd_entry(gxp, offs, F0);
- ldx_entry(gxp, offs, O5);
- ldx_entry(gxp, offs, O4);
- ldx_entry(gxp, offs, O3);
- ldx_entry(gxp, offs, O2);
- ldx_entry(gxp, offs, O1);
- ldx_entry(gxp, offs, O0);
-
- __ save(SP, -176, SP);
-
- const Register addr = gxp; // Alright to reuse 'gxp'.
-
- // Dispatch relative current PC, into instruction table below.
- __ rdpc(addr);
- __ add(addr, 16, addr);
- __ jmp(addr, disp);
- __ delayed()->clr(offs);
-
- ldd_entry(gyp, offs, F58);
- ldd_entry(gyp, offs, F56);
- ldd_entry(gyp, offs, F54);
- ldd_entry(gyp, offs, F52);
- ldd_entry(gyp, offs, F50);
- ldd_entry(gyp, offs, F48);
- ldd_entry(gyp, offs, F46);
- ldd_entry(gyp, offs, F44);
- ldd_entry(gyp, offs, F42);
- ldd_entry(gyp, offs, F40);
- ldd_entry(gyp, offs, F38);
- ldd_entry(gyp, offs, F36);
- ldd_entry(gyp, offs, F34);
- ldd_entry(gyp, offs, F32);
- ldd_entry(gyp, offs, F30);
- ldd_entry(gyp, offs, F28);
- ldd_entry(gyp, offs, F26);
- ldd_entry(gyp, offs, F24);
- ldx_entry(gyp, offs, O5);
- ldx_entry(gyp, offs, O4);
- ldx_entry(gyp, offs, O3);
- ldx_entry(gyp, offs, O2);
- ldx_entry(gyp, offs, O1);
- ldx_entry(gyp, offs, O0);
- ldx_entry(gyp, offs, L7);
- ldx_entry(gyp, offs, L6);
- ldx_entry(gyp, offs, L5);
- ldx_entry(gyp, offs, L4);
- ldx_entry(gyp, offs, L3);
- ldx_entry(gyp, offs, L2);
- ldx_entry(gyp, offs, L1);
- ldx_entry(gyp, offs, L0);
-
- __ save(SP, -176, SP);
- __ save(SP, -176, SP);
- __ save(SP, -176, SP);
- __ save(SP, -176, SP);
- __ save(SP, -176, SP);
-
- Label L_mpmul_restore_4, L_mpmul_restore_3, L_mpmul_restore_2;
- Label L_mpmul_restore_1, L_mpmul_restore_0;
-
- // Dispatch relative current PC, into instruction table below.
- __ rdpc(addr);
- __ add(addr, 16, addr);
- __ jmp(addr, disp);
- __ delayed()->clr(offs);
-
- mpmul_entry(31, L_mpmul_restore_0);
- mpmul_entry(30, L_mpmul_restore_0);
- mpmul_entry(29, L_mpmul_restore_0);
- mpmul_entry(28, L_mpmul_restore_0);
- mpmul_entry(27, L_mpmul_restore_1);
- mpmul_entry(26, L_mpmul_restore_1);
- mpmul_entry(25, L_mpmul_restore_1);
- mpmul_entry(24, L_mpmul_restore_1);
- mpmul_entry(23, L_mpmul_restore_1);
- mpmul_entry(22, L_mpmul_restore_1);
- mpmul_entry(21, L_mpmul_restore_1);
- mpmul_entry(20, L_mpmul_restore_2);
- mpmul_entry(19, L_mpmul_restore_2);
- mpmul_entry(18, L_mpmul_restore_2);
- mpmul_entry(17, L_mpmul_restore_2);
- mpmul_entry(16, L_mpmul_restore_2);
- mpmul_entry(15, L_mpmul_restore_2);
- mpmul_entry(14, L_mpmul_restore_2);
- mpmul_entry(13, L_mpmul_restore_3);
- mpmul_entry(12, L_mpmul_restore_3);
- mpmul_entry(11, L_mpmul_restore_3);
- mpmul_entry(10, L_mpmul_restore_3);
- mpmul_entry( 9, L_mpmul_restore_3);
- mpmul_entry( 8, L_mpmul_restore_3);
- mpmul_entry( 7, L_mpmul_restore_3);
- mpmul_entry( 6, L_mpmul_restore_4);
- mpmul_entry( 5, L_mpmul_restore_4);
- mpmul_entry( 4, L_mpmul_restore_4);
- mpmul_entry( 3, L_mpmul_restore_4);
- mpmul_entry( 2, L_mpmul_restore_4);
- mpmul_entry( 1, L_mpmul_restore_4);
- mpmul_entry( 0, L_mpmul_restore_4);
-
- Label L_z31, L_z30, L_z29, L_z28, L_z27, L_z26, L_z25, L_z24;
- Label L_z23, L_z22, L_z21, L_z20, L_z19, L_z18, L_z17, L_z16;
- Label L_z15, L_z14, L_z13, L_z12, L_z11, L_z10, L_z09, L_z08;
- Label L_z07, L_z06, L_z05, L_z04, L_z03, L_z02, L_z01, L_z00;
-
- Label L_zst_base; // Store sequence base address.
- __ bind(L_zst_base);
-
- stx_entry(L_z31, L7, L6, gzp, offs);
- stx_entry(L_z30, L5, L4, gzp, offs);
- stx_entry(L_z29, L3, L2, gzp, offs);
- stx_entry(L_z28, L1, L0, gzp, offs);
- __ restore();
- stx_entry(L_z27, O5, O4, gzp, offs);
- stx_entry(L_z26, O3, O2, gzp, offs);
- stx_entry(L_z25, O1, O0, gzp, offs);
- stx_entry(L_z24, L7, L6, gzp, offs);
- stx_entry(L_z23, L5, L4, gzp, offs);
- stx_entry(L_z22, L3, L2, gzp, offs);
- stx_entry(L_z21, L1, L0, gzp, offs);
- __ restore();
- stx_entry(L_z20, O5, O4, gzp, offs);
- stx_entry(L_z19, O3, O2, gzp, offs);
- stx_entry(L_z18, O1, O0, gzp, offs);
- stx_entry(L_z17, L7, L6, gzp, offs);
- stx_entry(L_z16, L5, L4, gzp, offs);
- stx_entry(L_z15, L3, L2, gzp, offs);
- stx_entry(L_z14, L1, L0, gzp, offs);
- __ restore();
- stx_entry(L_z13, O5, O4, gzp, offs);
- stx_entry(L_z12, O3, O2, gzp, offs);
- stx_entry(L_z11, O1, O0, gzp, offs);
- stx_entry(L_z10, L7, L6, gzp, offs);
- stx_entry(L_z09, L5, L4, gzp, offs);
- stx_entry(L_z08, L3, L2, gzp, offs);
- stx_entry(L_z07, L1, L0, gzp, offs);
- __ restore();
- stx_entry(L_z06, O5, O4, gzp, offs);
- stx_entry(L_z05, O3, O2, gzp, offs);
- stx_entry(L_z04, O1, O0, gzp, offs);
- stx_entry(L_z03, L7, L6, gzp, offs);
- stx_entry(L_z02, L5, L4, gzp, offs);
- stx_entry(L_z01, L3, L2, gzp, offs);
- stx_entry(L_z00, L1, L0, gzp, offs);
-
- __ restore();
- __ restore();
- // Exit out of 'mpmul' routine, back to multiplyToLen.
- __ ba_short(L_exit);
-
- Label L_zst_offs;
- __ bind(L_zst_offs);
-
- offs_entry(L_z31, L_zst_base); // index 31: 2048x2048
- offs_entry(L_z30, L_zst_base);
- offs_entry(L_z29, L_zst_base);
- offs_entry(L_z28, L_zst_base);
- offs_entry(L_z27, L_zst_base);
- offs_entry(L_z26, L_zst_base);
- offs_entry(L_z25, L_zst_base);
- offs_entry(L_z24, L_zst_base);
- offs_entry(L_z23, L_zst_base);
- offs_entry(L_z22, L_zst_base);
- offs_entry(L_z21, L_zst_base);
- offs_entry(L_z20, L_zst_base);
- offs_entry(L_z19, L_zst_base);
- offs_entry(L_z18, L_zst_base);
- offs_entry(L_z17, L_zst_base);
- offs_entry(L_z16, L_zst_base);
- offs_entry(L_z15, L_zst_base);
- offs_entry(L_z14, L_zst_base);
- offs_entry(L_z13, L_zst_base);
- offs_entry(L_z12, L_zst_base);
- offs_entry(L_z11, L_zst_base);
- offs_entry(L_z10, L_zst_base);
- offs_entry(L_z09, L_zst_base);
- offs_entry(L_z08, L_zst_base);
- offs_entry(L_z07, L_zst_base);
- offs_entry(L_z06, L_zst_base);
- offs_entry(L_z05, L_zst_base);
- offs_entry(L_z04, L_zst_base);
- offs_entry(L_z03, L_zst_base);
- offs_entry(L_z02, L_zst_base);
- offs_entry(L_z01, L_zst_base);
- offs_entry(L_z00, L_zst_base); // index 0: 64x64
-
- __ bind(L_mpmul_restore_4);
- __ restore();
- __ bind(L_mpmul_restore_3);
- __ restore();
- __ bind(L_mpmul_restore_2);
- __ restore();
- __ bind(L_mpmul_restore_1);
- __ restore();
- __ bind(L_mpmul_restore_0);
-
- // Dispatch via offset vector entry, into z-store sequence.
- Label L_zst_rdpc;
- __ bind(L_zst_rdpc);
-
- assert(L_zst_base.is_bound(), "must be");
- assert(L_zst_offs.is_bound(), "must be");
- assert(L_zst_rdpc.is_bound(), "must be");
-
- int dbase = L_zst_rdpc.loc_pos() - L_zst_base.loc_pos();
- int doffs = L_zst_rdpc.loc_pos() - L_zst_offs.loc_pos();
-
- temp = gyp; // Alright to reuse 'gyp'.
-
- __ rdpc(addr);
- __ sub(addr, doffs, temp);
- __ srlx(disp, 1, disp);
- __ lduw(temp, disp, offs);
- __ sub(addr, dbase, temp);
- __ jmp(temp, offs);
- __ delayed()->clr(offs);
- }
-
- void gen_mult_64x64(Register xp, Register xn,
- Register yp, Register yn,
- Register zp, Register zn, Label &L_exit)
- {
- // Assuming that a stack frame has already been created, i.e. local and
- // output registers are available for immediate use.
-
- const Register ri = L0; // Outer loop index, xv[i]
- const Register rj = L1; // Inner loop index, yv[j]
- const Register rk = L2; // Output loop index, zv[k]
- const Register rx = L4; // x-vector datum [i]
- const Register ry = L5; // y-vector datum [j]
- const Register rz = L6; // z-vector datum [k]
- const Register rc = L7; // carry over (to z-vector datum [k-1])
-
- const Register lop = O0; // lo-64b product
- const Register hip = O1; // hi-64b product
-
- const Register zero = G0;
-
- Label L_loop_i, L_exit_loop_i;
- Label L_loop_j;
- Label L_loop_i2, L_exit_loop_i2;
-
- __ srlx(xn, 1, xn); // index for u32 to u64 ditto
- __ srlx(yn, 1, yn); // index for u32 to u64 ditto
- __ srlx(zn, 1, zn); // index for u32 to u64 ditto
- __ dec(xn); // Adjust [0..(N/2)-1]
- __ dec(yn);
- __ dec(zn);
- __ clr(rc); // u64 c = 0
- __ sllx(xn, 3, ri); // int i = xn (byte offset i = 8*xn)
- __ sllx(yn, 3, rj); // int j = yn (byte offset i = 8*xn)
- __ sllx(zn, 3, rk); // int k = zn (byte offset k = 8*zn)
- __ ldx(yp, rj, ry); // u64 y = yp[yn]
-
- // for (int i = xn; i >= 0; i--)
- __ bind(L_loop_i);
-
- __ cmp_and_br_short(ri, 0, // i >= 0
- Assembler::less, Assembler::pn, L_exit_loop_i);
- __ ldx(xp, ri, rx); // x = xp[i]
- __ mulx(rx, ry, lop); // lo-64b-part of result 64x64
- __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64
- __ addcc(rc, lop, lop); // Accumulate lower order bits (producing carry)
- __ addxc(hip, zero, rc); // carry over to next datum [k-1]
- __ stx(lop, zp, rk); // z[k] = lop
- __ dec(rk, 8); // k--
- __ dec(ri, 8); // i--
- __ ba_short(L_loop_i);
-
- __ bind(L_exit_loop_i);
- __ stx(rc, zp, rk); // z[k] = c
-
- // for (int j = yn - 1; j >= 0; j--)
- __ sllx(yn, 3, rj); // int j = yn - 1 (byte offset j = 8*yn)
- __ dec(rj, 8);
-
- __ bind(L_loop_j);
-
- __ cmp_and_br_short(rj, 0, // j >= 0
- Assembler::less, Assembler::pn, L_exit);
- __ clr(rc); // u64 c = 0
- __ ldx(yp, rj, ry); // u64 y = yp[j]
-
- // for (int i = xn, k = --zn; i >= 0; i--)
- __ dec(zn); // --zn
- __ sllx(xn, 3, ri); // int i = xn (byte offset i = 8*xn)
- __ sllx(zn, 3, rk); // int k = zn (byte offset k = 8*zn)
-
- __ bind(L_loop_i2);
-
- __ cmp_and_br_short(ri, 0, // i >= 0
- Assembler::less, Assembler::pn, L_exit_loop_i2);
- __ ldx(xp, ri, rx); // x = xp[i]
- __ ldx(zp, rk, rz); // z = zp[k], accumulator
- __ mulx(rx, ry, lop); // lo-64b-part of result 64x64
- __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64
- __ addcc(rz, rc, rz); // Accumulate lower order bits,
- __ addxc(hip, zero, rc); // Accumulate higher order bits to carry
- __ addcc(rz, lop, rz); // z += lo(p) + c
- __ addxc(rc, zero, rc);
- __ stx(rz, zp, rk); // zp[k] = z
- __ dec(rk, 8); // k--
- __ dec(ri, 8); // i--
- __ ba_short(L_loop_i2);
-
- __ bind(L_exit_loop_i2);
- __ stx(rc, zp, rk); // z[k] = c
- __ dec(rj, 8); // j--
- __ ba_short(L_loop_j);
- }
-
- void gen_mult_64x64_unaligned(Register xp, Register xn,
- Register yp, Register yn,
- Register zp, Register zn, Label &L_exit)
- {
- // Assuming that a stack frame has already been created, i.e. local and
- // output registers are available for use.
-
- const Register xpc = L0; // Outer loop cursor, xp[i]
- const Register ypc = L1; // Inner loop cursor, yp[j]
- const Register zpc = L2; // Output loop cursor, zp[k]
- const Register rx = L4; // x-vector datum [i]
- const Register ry = L5; // y-vector datum [j]
- const Register rz = L6; // z-vector datum [k]
- const Register rc = L7; // carry over (to z-vector datum [k-1])
- const Register rt = O2;
-
- const Register lop = O0; // lo-64b product
- const Register hip = O1; // hi-64b product
-
- const Register zero = G0;
-
- Label L_loop_i, L_exit_loop_i;
- Label L_loop_j;
- Label L_loop_i2, L_exit_loop_i2;
-
- __ srlx(xn, 1, xn); // index for u32 to u64 ditto
- __ srlx(yn, 1, yn); // index for u32 to u64 ditto
- __ srlx(zn, 1, zn); // index for u32 to u64 ditto
- __ dec(xn); // Adjust [0..(N/2)-1]
- __ dec(yn);
- __ dec(zn);
- __ clr(rc); // u64 c = 0
- __ sllx(xn, 3, xpc); // u32* xpc = &xp[xn] (byte offset 8*xn)
- __ add(xp, xpc, xpc);
- __ sllx(yn, 3, ypc); // u32* ypc = &yp[yn] (byte offset 8*yn)
- __ add(yp, ypc, ypc);
- __ sllx(zn, 3, zpc); // u32* zpc = &zp[zn] (byte offset 8*zn)
- __ add(zp, zpc, zpc);
- __ lduw(ypc, 0, rt); // u64 y = yp[yn]
- __ lduw(ypc, 4, ry); // ...
- __ sllx(rt, 32, rt);
- __ or3(rt, ry, ry);
-
- // for (int i = xn; i >= 0; i--)
- __ bind(L_loop_i);
-
- __ cmp_and_brx_short(xpc, xp,// i >= 0
- Assembler::lessUnsigned, Assembler::pn, L_exit_loop_i);
- __ lduw(xpc, 0, rt); // u64 x = xp[i]
- __ lduw(xpc, 4, rx); // ...
- __ sllx(rt, 32, rt);
- __ or3(rt, rx, rx);
- __ mulx(rx, ry, lop); // lo-64b-part of result 64x64
- __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64
- __ addcc(rc, lop, lop); // Accumulate lower order bits (producing carry)
- __ addxc(hip, zero, rc); // carry over to next datum [k-1]
- __ srlx(lop, 32, rt);
- __ stw(rt, zpc, 0); // z[k] = lop
- __ stw(lop, zpc, 4); // ...
- __ dec(zpc, 8); // k-- (zpc--)
- __ dec(xpc, 8); // i-- (xpc--)
- __ ba_short(L_loop_i);
-
- __ bind(L_exit_loop_i);
- __ srlx(rc, 32, rt);
- __ stw(rt, zpc, 0); // z[k] = c
- __ stw(rc, zpc, 4);
-
- // for (int j = yn - 1; j >= 0; j--)
- __ sllx(yn, 3, ypc); // u32* ypc = &yp[yn] (byte offset 8*yn)
- __ add(yp, ypc, ypc);
- __ dec(ypc, 8); // yn - 1 (ypc--)
-
- __ bind(L_loop_j);
-
- __ cmp_and_brx_short(ypc, yp,// j >= 0
- Assembler::lessUnsigned, Assembler::pn, L_exit);
- __ clr(rc); // u64 c = 0
- __ lduw(ypc, 0, rt); // u64 y = yp[j] (= *ypc)
- __ lduw(ypc, 4, ry); // ...
- __ sllx(rt, 32, rt);
- __ or3(rt, ry, ry);
-
- // for (int i = xn, k = --zn; i >= 0; i--)
- __ sllx(xn, 3, xpc); // u32* xpc = &xp[xn] (byte offset 8*xn)
- __ add(xp, xpc, xpc);
- __ dec(zn); // --zn
- __ sllx(zn, 3, zpc); // u32* zpc = &zp[zn] (byte offset 8*zn)
- __ add(zp, zpc, zpc);
-
- __ bind(L_loop_i2);
-
- __ cmp_and_brx_short(xpc, xp,// i >= 0
- Assembler::lessUnsigned, Assembler::pn, L_exit_loop_i2);
- __ lduw(xpc, 0, rt); // u64 x = xp[i] (= *xpc)
- __ lduw(xpc, 4, rx); // ...
- __ sllx(rt, 32, rt);
- __ or3(rt, rx, rx);
-
- __ lduw(zpc, 0, rt); // u64 z = zp[k] (= *zpc)
- __ lduw(zpc, 4, rz); // ...
- __ sllx(rt, 32, rt);
- __ or3(rt, rz, rz);
-
- __ mulx(rx, ry, lop); // lo-64b-part of result 64x64
- __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64
- __ addcc(rz, rc, rz); // Accumulate lower order bits...
- __ addxc(hip, zero, rc); // Accumulate higher order bits to carry
- __ addcc(rz, lop, rz); // ... z += lo(p) + c
- __ addxccc(rc, zero, rc);
- __ srlx(rz, 32, rt);
- __ stw(rt, zpc, 0); // zp[k] = z (*zpc = z)
- __ stw(rz, zpc, 4);
- __ dec(zpc, 8); // k-- (zpc--)
- __ dec(xpc, 8); // i-- (xpc--)
- __ ba_short(L_loop_i2);
-
- __ bind(L_exit_loop_i2);
- __ srlx(rc, 32, rt);
- __ stw(rt, zpc, 0); // z[k] = c
- __ stw(rc, zpc, 4);
- __ dec(ypc, 8); // j-- (ypc--)
- __ ba_short(L_loop_j);
- }
-
- void gen_mult_32x32(Register xp, Register xn,
- Register yp, Register yn,
- Register zp, Register zn, Label &L_exit)
- {
- // Assuming that a stack frame has already been created, i.e. local and
- // output registers are available for use.
-
- const Register ri = L0; // Outer loop index, xv[i]
- const Register rj = L1; // Inner loop index, yv[j]
- const Register rk = L2; // Output loop index, zv[k]
- const Register rx = L4; // x-vector datum [i]
- const Register ry = L5; // y-vector datum [j]
- const Register rz = L6; // z-vector datum [k]
- const Register rc = L7; // carry over (to z-vector datum [k-1])
-
- const Register p64 = O0; // 64b product
- const Register z65 = O1; // carry+64b accumulator
- const Register c65 = O2; // carry at bit 65
- const Register c33 = O2; // carry at bit 33 (after shift)
-
- const Register zero = G0;
-
- Label L_loop_i, L_exit_loop_i;
- Label L_loop_j;
- Label L_loop_i2, L_exit_loop_i2;
-
- __ dec(xn); // Adjust [0..N-1]
- __ dec(yn);
- __ dec(zn);
- __ clr(rc); // u32 c = 0
- __ sllx(xn, 2, ri); // int i = xn (byte offset i = 4*xn)
- __ sllx(yn, 2, rj); // int j = yn (byte offset i = 4*xn)
- __ sllx(zn, 2, rk); // int k = zn (byte offset k = 4*zn)
- __ lduw(yp, rj, ry); // u32 y = yp[yn]
-
- // for (int i = xn; i >= 0; i--)
- __ bind(L_loop_i);
-
- __ cmp_and_br_short(ri, 0, // i >= 0
- Assembler::less, Assembler::pn, L_exit_loop_i);
- __ lduw(xp, ri, rx); // x = xp[i]
- __ mulx(rx, ry, p64); // 64b result of 32x32
- __ addcc(rc, p64, z65); // Accumulate to 65 bits (producing carry)
- __ addxc(zero, zero, c65); // Materialise carry (in bit 65) into lsb,
- __ sllx(c65, 32, c33); // and shift into bit 33
- __ srlx(z65, 32, rc); // carry = c33 | hi(z65) >> 32
- __ add(c33, rc, rc); // carry over to next datum [k-1]
- __ stw(z65, zp, rk); // z[k] = lo(z65)
- __ dec(rk, 4); // k--
- __ dec(ri, 4); // i--
- __ ba_short(L_loop_i);
-
- __ bind(L_exit_loop_i);
- __ stw(rc, zp, rk); // z[k] = c
-
- // for (int j = yn - 1; j >= 0; j--)
- __ sllx(yn, 2, rj); // int j = yn - 1 (byte offset j = 4*yn)
- __ dec(rj, 4);
-
- __ bind(L_loop_j);
-
- __ cmp_and_br_short(rj, 0, // j >= 0
- Assembler::less, Assembler::pn, L_exit);
- __ clr(rc); // u32 c = 0
- __ lduw(yp, rj, ry); // u32 y = yp[j]
-
- // for (int i = xn, k = --zn; i >= 0; i--)
- __ dec(zn); // --zn
- __ sllx(xn, 2, ri); // int i = xn (byte offset i = 4*xn)
- __ sllx(zn, 2, rk); // int k = zn (byte offset k = 4*zn)
-
- __ bind(L_loop_i2);
-
- __ cmp_and_br_short(ri, 0, // i >= 0
- Assembler::less, Assembler::pn, L_exit_loop_i2);
- __ lduw(xp, ri, rx); // x = xp[i]
- __ lduw(zp, rk, rz); // z = zp[k], accumulator
- __ mulx(rx, ry, p64); // 64b result of 32x32
- __ add(rz, rc, rz); // Accumulate lower order bits,
- __ addcc(rz, p64, z65); // z += lo(p64) + c
- __ addxc(zero, zero, c65); // Materialise carry (in bit 65) into lsb,
- __ sllx(c65, 32, c33); // and shift into bit 33
- __ srlx(z65, 32, rc); // carry = c33 | hi(z65) >> 32
- __ add(c33, rc, rc); // carry over to next datum [k-1]
- __ stw(z65, zp, rk); // zp[k] = lo(z65)
- __ dec(rk, 4); // k--
- __ dec(ri, 4); // i--
- __ ba_short(L_loop_i2);
-
- __ bind(L_exit_loop_i2);
- __ stw(rc, zp, rk); // z[k] = c
- __ dec(rj, 4); // j--
- __ ba_short(L_loop_j);
- }
-
-
- void generate_initial() {
- // Generates all stubs and initializes the entry points
-
- //------------------------------------------------------------------------------------------------------------------------
- // entry points that exist in all platforms
- // Note: This is code that could be shared among different platforms - however the benefit seems to be smaller than
- // the disadvantage of having a much more complicated generator structure. See also comment in stubRoutines.hpp.
- StubRoutines::_forward_exception_entry = generate_forward_exception();
-
- StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address);
- StubRoutines::_catch_exception_entry = generate_catch_exception();
-
- //------------------------------------------------------------------------------------------------------------------------
- // entry points that are platform specific
- StubRoutines::Sparc::_test_stop_entry = generate_test_stop();
-
- StubRoutines::Sparc::_stop_subroutine_entry = generate_stop_subroutine();
- StubRoutines::Sparc::_flush_callers_register_windows_entry = generate_flush_callers_register_windows();
-
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError));
- StubRoutines::_throw_delayed_StackOverflowError_entry =
- generate_throw_exception("delayed StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError));
-
- if (UseCRC32Intrinsics) {
- // set table address before stub generation which use it
- StubRoutines::_crc_table_adr = (address)StubRoutines::Sparc::_crc_table;
- StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32();
- }
-
- if (UseCRC32CIntrinsics) {
- // set table address before stub generation which use it
- StubRoutines::_crc32c_table_addr = (address)StubRoutines::Sparc::_crc32c_table;
- StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C();
- }
-
- // Safefetch stubs.
- generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry,
- &StubRoutines::_safefetch32_fault_pc,
- &StubRoutines::_safefetch32_continuation_pc);
- generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry,
- &StubRoutines::_safefetchN_fault_pc,
- &StubRoutines::_safefetchN_continuation_pc);
- }
-
-
- void generate_all() {
- // Generates all stubs and initializes the entry points
-
- // Generate partial_subtype_check first here since its code depends on
- // UseZeroBaseCompressedOops which is defined after heap initialization.
- StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check();
- // These entry points require SharedInfo::stack0 to be set up in non-core builds
- StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError));
- StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError));
- StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call));
-
- // support for verify_oop (must happen after universe_init)
- StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine();
-
- // arraycopy stubs used by compilers
- generate_arraycopy_stubs();
-
- // Don't initialize the platform math functions since sparc
- // doesn't have intrinsics for these operations.
-
- // generate AES intrinsics code
- if (UseAESIntrinsics) {
- StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock();
- StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock();
- StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
- StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel();
- }
- // generate GHASH intrinsics code
- if (UseGHASHIntrinsics) {
- StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks();
- }
-
- // generate SHA1/SHA256/SHA512 intrinsics code
- if (UseSHA1Intrinsics) {
- StubRoutines::_sha1_implCompress = generate_sha1_implCompress(false, "sha1_implCompress");
- StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB");
- }
- if (UseSHA256Intrinsics) {
- StubRoutines::_sha256_implCompress = generate_sha256_implCompress(false, "sha256_implCompress");
- StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(true, "sha256_implCompressMB");
- }
- if (UseSHA512Intrinsics) {
- StubRoutines::_sha512_implCompress = generate_sha512_implCompress(false, "sha512_implCompress");
- StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(true, "sha512_implCompressMB");
- }
- // generate Adler32 intrinsics code
- if (UseAdler32Intrinsics) {
- StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32();
- }
-
-#ifdef COMPILER2
- // Intrinsics supported by C2 only:
- if (UseMultiplyToLenIntrinsic) {
- StubRoutines::_multiplyToLen = generate_multiplyToLen();
- }
-#endif // COMPILER2
- }
-
- public:
- StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {
- // replace the standard masm with a special one:
- _masm = new MacroAssembler(code);
-
- _stub_count = !all ? 0x100 : 0x200;
- if (all) {
- generate_all();
- } else {
- generate_initial();
- }
-
- // make sure this stub is available for all local calls
- if (_atomic_add_stub.is_unbound()) {
- // generate a second time, if necessary
- (void) generate_atomic_add();
- }
- }
-
-
- private:
- int _stub_count;
- void stub_prolog(StubCodeDesc* cdesc) {
- # ifdef ASSERT
- // put extra information in the stub code, to make it more readable
- // Write the high part of the address
- // [RGV] Check if there is a dependency on the size of this prolog
- __ emit_data((intptr_t)cdesc >> 32, relocInfo::none);
- __ emit_data((intptr_t)cdesc, relocInfo::none);
- __ emit_data(++_stub_count, relocInfo::none);
- # endif
- align(true);
- }
-
- void align(bool at_header = false) {
- // %%%%% move this constant somewhere else
- // UltraSPARC cache line size is 8 instructions:
- const unsigned int icache_line_size = 32;
- const unsigned int icache_half_line_size = 16;
-
- if (at_header) {
- while ((intptr_t)(__ pc()) % icache_line_size != 0) {
- __ emit_data(0, relocInfo::none);
- }
- } else {
- while ((intptr_t)(__ pc()) % icache_half_line_size != 0) {
- __ nop();
- }
- }
- }
-
-}; // end class declaration
-
-#define UCM_TABLE_MAX_ENTRIES 8
-void StubGenerator_generate(CodeBuffer* code, bool all) {
- if (UnsafeCopyMemory::_table == NULL) {
- UnsafeCopyMemory::create_table(UCM_TABLE_MAX_ENTRIES);
- }
- StubGenerator g(code, all);
-}
diff --git a/src/hotspot/cpu/sparc/stubRoutines_sparc.cpp b/src/hotspot/cpu/sparc/stubRoutines_sparc.cpp
deleted file mode 100644
index 63cbcf05945..00000000000
--- a/src/hotspot/cpu/sparc/stubRoutines_sparc.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 1997, 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 "runtime/deoptimization.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/thread.inline.hpp"
-
-// Implementation of the platform-specific part of StubRoutines - for
-// a description of how to extend it, see the stubRoutines.hpp file.
-
-
-extern "C" {
- address _flush_reg_windows(); // in .s file.
- // Flush registers to stack. In case of error we will need to stack walk.
- address bootstrap_flush_windows(void) {
- Thread* thread = Thread::current_or_null();
- // Very early in process there is no thread.
- if (thread != NULL) {
- guarantee(thread->is_Java_thread(), "Not a Java thread.");
- JavaThread* jt = (JavaThread*)thread;
- guarantee(!jt->has_last_Java_frame(), "Must be able to flush registers!");
- }
- return (address)_flush_reg_windows();
- };
-};
-
-address StubRoutines::Sparc::_test_stop_entry = NULL;
-address StubRoutines::Sparc::_stop_subroutine_entry = NULL;
-address StubRoutines::Sparc::_flush_callers_register_windows_entry = CAST_FROM_FN_PTR(address, bootstrap_flush_windows);
-
-address StubRoutines::Sparc::_partial_subtype_check = NULL;
-
-uint64_t StubRoutines::Sparc::_crc_by128_masks[] =
-{
- /* The fields in this structure are arranged so that they can be
- * picked up two at a time with 128-bit loads.
- *
- * Because of flipped bit order for this CRC polynomials
- * the constant for X**N is left-shifted by 1. This is because
- * a 64 x 64 polynomial multiply produces a 127-bit result
- * but the highest term is always aligned to bit 0 in the container.
- * Pre-shifting by one fixes this, at the cost of potentially making
- * the 32-bit constant no longer fit in a 32-bit container (thus the
- * use of uint64_t, though this is also the size used by the carry-
- * less multiply instruction.
- *
- * In addition, the flipped bit order and highest-term-at-least-bit
- * multiply changes the constants used. The 96-bit result will be
- * aligned to the high-term end of the target 128-bit container,
- * not the low-term end; that is, instead of a 512-bit or 576-bit fold,
- * instead it is a 480 (=512-32) or 544 (=512+64-32) bit fold.
- *
- * This cause additional problems in the 128-to-64-bit reduction; see the
- * code for details. By storing a mask in the otherwise unused half of
- * a 128-bit constant, bits can be cleared before multiplication without
- * storing and reloading. Note that staying on a 128-bit datapath means
- * that some data is uselessly stored and some unused data is intersected
- * with an irrelevant constant.
- */
-
- ((uint64_t) 0xffffffffUL), /* low of K_M_64 */
- ((uint64_t) 0xb1e6b092U << 1), /* high of K_M_64 */
- ((uint64_t) 0xba8ccbe8U << 1), /* low of K_160_96 */
- ((uint64_t) 0x6655004fU << 1), /* high of K_160_96 */
- ((uint64_t) 0xaa2215eaU << 1), /* low of K_544_480 */
- ((uint64_t) 0xe3720acbU << 1) /* high of K_544_480 */
-};
-
-/**
- * crc_table[] from jdk/src/java.base/share/native/libzip/zlib-1.2.8/crc32.h
- */
-juint StubRoutines::Sparc::_crc_table[] =
-{
- 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
- 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
- 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
- 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
- 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
- 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
- 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
- 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
- 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
- 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
- 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
- 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
- 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
- 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
- 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
- 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
- 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
- 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
- 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
- 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
- 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
- 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
- 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
- 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
- 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
- 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
- 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
- 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
- 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
- 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
- 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
- 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
- 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
- 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
- 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
- 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
- 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
- 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
- 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
- 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
- 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
- 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
- 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
- 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
- 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
- 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
- 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
- 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
- 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
- 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
- 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
- 0x2d02ef8dUL
-};
-
-/**
- * CRC32C constants lookup table
- */
-juint StubRoutines::Sparc::_crc32c_table[] =
-{
- 0x00000000UL, 0xF26B8303UL, 0xE13B70F7UL, 0x1350F3F4UL, 0xC79A971FUL,
- 0x35F1141CUL, 0x26A1E7E8UL, 0xD4CA64EBUL, 0x8AD958CFUL, 0x78B2DBCCUL,
- 0x6BE22838UL, 0x9989AB3BUL, 0x4D43CFD0UL, 0xBF284CD3UL, 0xAC78BF27UL,
- 0x5E133C24UL, 0x105EC76FUL, 0xE235446CUL, 0xF165B798UL, 0x030E349BUL,
- 0xD7C45070UL, 0x25AFD373UL, 0x36FF2087UL, 0xC494A384UL, 0x9A879FA0UL,
- 0x68EC1CA3UL, 0x7BBCEF57UL, 0x89D76C54UL, 0x5D1D08BFUL, 0xAF768BBCUL,
- 0xBC267848UL, 0x4E4DFB4BUL, 0x20BD8EDEUL, 0xD2D60DDDUL, 0xC186FE29UL,
- 0x33ED7D2AUL, 0xE72719C1UL, 0x154C9AC2UL, 0x061C6936UL, 0xF477EA35UL,
- 0xAA64D611UL, 0x580F5512UL, 0x4B5FA6E6UL, 0xB93425E5UL, 0x6DFE410EUL,
- 0x9F95C20DUL, 0x8CC531F9UL, 0x7EAEB2FAUL, 0x30E349B1UL, 0xC288CAB2UL,
- 0xD1D83946UL, 0x23B3BA45UL, 0xF779DEAEUL, 0x05125DADUL, 0x1642AE59UL,
- 0xE4292D5AUL, 0xBA3A117EUL, 0x4851927DUL, 0x5B016189UL, 0xA96AE28AUL,
- 0x7DA08661UL, 0x8FCB0562UL, 0x9C9BF696UL, 0x6EF07595UL, 0x417B1DBCUL,
- 0xB3109EBFUL, 0xA0406D4BUL, 0x522BEE48UL, 0x86E18AA3UL, 0x748A09A0UL,
- 0x67DAFA54UL, 0x95B17957UL, 0xCBA24573UL, 0x39C9C670UL, 0x2A993584UL,
- 0xD8F2B687UL, 0x0C38D26CUL, 0xFE53516FUL, 0xED03A29BUL, 0x1F682198UL,
- 0x5125DAD3UL, 0xA34E59D0UL, 0xB01EAA24UL, 0x42752927UL, 0x96BF4DCCUL,
- 0x64D4CECFUL, 0x77843D3BUL, 0x85EFBE38UL, 0xDBFC821CUL, 0x2997011FUL,
- 0x3AC7F2EBUL, 0xC8AC71E8UL, 0x1C661503UL, 0xEE0D9600UL, 0xFD5D65F4UL,
- 0x0F36E6F7UL, 0x61C69362UL, 0x93AD1061UL, 0x80FDE395UL, 0x72966096UL,
- 0xA65C047DUL, 0x5437877EUL, 0x4767748AUL, 0xB50CF789UL, 0xEB1FCBADUL,
- 0x197448AEUL, 0x0A24BB5AUL, 0xF84F3859UL, 0x2C855CB2UL, 0xDEEEDFB1UL,
- 0xCDBE2C45UL, 0x3FD5AF46UL, 0x7198540DUL, 0x83F3D70EUL, 0x90A324FAUL,
- 0x62C8A7F9UL, 0xB602C312UL, 0x44694011UL, 0x5739B3E5UL, 0xA55230E6UL,
- 0xFB410CC2UL, 0x092A8FC1UL, 0x1A7A7C35UL, 0xE811FF36UL, 0x3CDB9BDDUL,
- 0xCEB018DEUL, 0xDDE0EB2AUL, 0x2F8B6829UL, 0x82F63B78UL, 0x709DB87BUL,
- 0x63CD4B8FUL, 0x91A6C88CUL, 0x456CAC67UL, 0xB7072F64UL, 0xA457DC90UL,
- 0x563C5F93UL, 0x082F63B7UL, 0xFA44E0B4UL, 0xE9141340UL, 0x1B7F9043UL,
- 0xCFB5F4A8UL, 0x3DDE77ABUL, 0x2E8E845FUL, 0xDCE5075CUL, 0x92A8FC17UL,
- 0x60C37F14UL, 0x73938CE0UL, 0x81F80FE3UL, 0x55326B08UL, 0xA759E80BUL,
- 0xB4091BFFUL, 0x466298FCUL, 0x1871A4D8UL, 0xEA1A27DBUL, 0xF94AD42FUL,
- 0x0B21572CUL, 0xDFEB33C7UL, 0x2D80B0C4UL, 0x3ED04330UL, 0xCCBBC033UL,
- 0xA24BB5A6UL, 0x502036A5UL, 0x4370C551UL, 0xB11B4652UL, 0x65D122B9UL,
- 0x97BAA1BAUL, 0x84EA524EUL, 0x7681D14DUL, 0x2892ED69UL, 0xDAF96E6AUL,
- 0xC9A99D9EUL, 0x3BC21E9DUL, 0xEF087A76UL, 0x1D63F975UL, 0x0E330A81UL,
- 0xFC588982UL, 0xB21572C9UL, 0x407EF1CAUL, 0x532E023EUL, 0xA145813DUL,
- 0x758FE5D6UL, 0x87E466D5UL, 0x94B49521UL, 0x66DF1622UL, 0x38CC2A06UL,
- 0xCAA7A905UL, 0xD9F75AF1UL, 0x2B9CD9F2UL, 0xFF56BD19UL, 0x0D3D3E1AUL,
- 0x1E6DCDEEUL, 0xEC064EEDUL, 0xC38D26C4UL, 0x31E6A5C7UL, 0x22B65633UL,
- 0xD0DDD530UL, 0x0417B1DBUL, 0xF67C32D8UL, 0xE52CC12CUL, 0x1747422FUL,
- 0x49547E0BUL, 0xBB3FFD08UL, 0xA86F0EFCUL, 0x5A048DFFUL, 0x8ECEE914UL,
- 0x7CA56A17UL, 0x6FF599E3UL, 0x9D9E1AE0UL, 0xD3D3E1ABUL, 0x21B862A8UL,
- 0x32E8915CUL, 0xC083125FUL, 0x144976B4UL, 0xE622F5B7UL, 0xF5720643UL,
- 0x07198540UL, 0x590AB964UL, 0xAB613A67UL, 0xB831C993UL, 0x4A5A4A90UL,
- 0x9E902E7BUL, 0x6CFBAD78UL, 0x7FAB5E8CUL, 0x8DC0DD8FUL, 0xE330A81AUL,
- 0x115B2B19UL, 0x020BD8EDUL, 0xF0605BEEUL, 0x24AA3F05UL, 0xD6C1BC06UL,
- 0xC5914FF2UL, 0x37FACCF1UL, 0x69E9F0D5UL, 0x9B8273D6UL, 0x88D28022UL,
- 0x7AB90321UL, 0xAE7367CAUL, 0x5C18E4C9UL, 0x4F48173DUL, 0xBD23943EUL,
- 0xF36E6F75UL, 0x0105EC76UL, 0x12551F82UL, 0xE03E9C81UL, 0x34F4F86AUL,
- 0xC69F7B69UL, 0xD5CF889DUL, 0x27A40B9EUL, 0x79B737BAUL, 0x8BDCB4B9UL,
- 0x988C474DUL, 0x6AE7C44EUL, 0xBE2DA0A5UL, 0x4C4623A6UL, 0x5F16D052UL,
- 0xAD7D5351UL
-};
diff --git a/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp b/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp
deleted file mode 100644
index 06669701238..00000000000
--- a/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_STUBROUTINES_SPARC_HPP
-#define CPU_SPARC_STUBROUTINES_SPARC_HPP
-
-// This file holds the platform specific parts of the StubRoutines
-// definition. See stubRoutines.hpp for a description on how to
-// extend it.
-
-
-// So unfortunately c2 will call with a pc from a frame object
-// (already adjusted) and a raw pc (unadjusted), so we need to check both.
-// It didn't use to be like this before adapter removal.
-static bool returns_to_call_stub(address return_pc) {
- return ((return_pc + frame::pc_return_offset) == _call_stub_return_address) ||
- (return_pc == _call_stub_return_address );
-}
-
-enum /* platform_dependent_constants */ {
- // %%%%%%%% May be able to shrink this a lot
- code_size1 = 20000, // simply increase if too small (assembler will crash if too small)
- code_size2 = 29000 // simply increase if too small (assembler will crash if too small)
-};
-
-class Sparc {
- friend class StubGenerator;
-
- private:
- static address _test_stop_entry;
- static address _stop_subroutine_entry;
- static address _flush_callers_register_windows_entry;
-
- static address _partial_subtype_check;
- // masks and table for CRC32
- static uint64_t _crc_by128_masks[];
- static juint _crc_table[];
- static juint _crc32c_table[];
-
- public:
- // test assembler stop routine by setting registers
- static void (*test_stop_entry()) () { return CAST_TO_FN_PTR(void (*)(void), _test_stop_entry); }
-
- // a subroutine for debugging assembler code
- static address stop_subroutine_entry_address() { return (address)&_stop_subroutine_entry; }
-
- // flushes (all but current) register window
- static intptr_t* (*flush_callers_register_windows_func())() { return CAST_TO_FN_PTR(intptr_t* (*)(void), _flush_callers_register_windows_entry); }
-
- static address partial_subtype_check() { return _partial_subtype_check; }
-
- static address crc_by128_masks_addr() { return (address)_crc_by128_masks; }
-};
-
-#endif // CPU_SPARC_STUBROUTINES_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp b/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp
deleted file mode 100644
index 0b5c0f3da86..00000000000
--- a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp
+++ /dev/null
@@ -1,1965 +0,0 @@
-/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "gc/shared/barrierSetAssembler.hpp"
-#include "interpreter/bytecodeHistogram.hpp"
-#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "interpreter/templateInterpreterGenerator.hpp"
-#include "interpreter/templateTable.hpp"
-#include "oops/arrayOop.hpp"
-#include "oops/methodData.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/jvmtiExport.hpp"
-#include "prims/jvmtiThreadState.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/deoptimization.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/synchronizer.hpp"
-#include "runtime/timer.hpp"
-#include "runtime/vframeArray.hpp"
-#include "utilities/align.hpp"
-#include "utilities/debug.hpp"
-#include "utilities/macros.hpp"
-
-// Size of interpreter code. Increase if too small. Interpreter will
-// fail with a guarantee ("not enough space for interpreter generation");
-// if too small.
-// Run with +PrintInterpreter to get the VM to print out the size.
-// Max size with JVMTI
-// The sethi() instruction generates lots more instructions when shell
-// stack limit is unlimited, so that's why this is much bigger.
-int TemplateInterpreter::InterpreterCodeSize = 260 * K;
-
-// Generation of Interpreter
-//
-// The TemplateInterpreterGenerator generates the interpreter into Interpreter::_code.
-
-
-#define __ _masm->
-
-
-//----------------------------------------------------------------------------------------------------
-
-// LP64 passes floating point arguments in F1, F3, F5, etc. instead of
-// O0, O1, O2 etc..
-// Doubles are passed in D0, D2, D4
-// We store the signature of the first 16 arguments in the first argument
-// slot because it will be overwritten prior to calling the native
-// function, with the pointer to the JNIEnv.
-// If LP64 there can be up to 16 floating point arguments in registers
-// or 6 integer registers.
-address TemplateInterpreterGenerator::generate_slow_signature_handler() {
-
- enum {
- non_float = 0,
- float_sig = 1,
- double_sig = 2,
- sig_mask = 3
- };
-
- address entry = __ pc();
- Argument argv(0, true);
-
- // We are in the jni transition frame. Save the last_java_frame corresponding to the
- // outer interpreter frame
- //
- __ set_last_Java_frame(FP, noreg);
- // make sure the interpreter frame we've pushed has a valid return pc
- __ mov(O7, I7);
- __ mov(Lmethod, G3_scratch);
- __ mov(Llocals, G4_scratch);
- __ save_frame(0);
- __ mov(G2_thread, L7_thread_cache);
- __ add(argv.address_in_frame(), O3);
- __ mov(G2_thread, O0);
- __ mov(G3_scratch, O1);
- __ call(CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), relocInfo::runtime_call_type);
- __ delayed()->mov(G4_scratch, O2);
- __ mov(L7_thread_cache, G2_thread);
- __ reset_last_Java_frame();
-
-
- // load the register arguments (the C code packed them as varargs)
- Address Sig = argv.address_in_frame(); // Argument 0 holds the signature
- __ ld_ptr( Sig, G3_scratch ); // Get register argument signature word into G3_scratch
- __ mov( G3_scratch, G4_scratch);
- __ srl( G4_scratch, 2, G4_scratch); // Skip Arg 0
- Label done;
- for (Argument ldarg = argv.successor(); ldarg.is_float_register(); ldarg = ldarg.successor()) {
- Label NonFloatArg;
- Label LoadFloatArg;
- Label LoadDoubleArg;
- Label NextArg;
- Address a = ldarg.address_in_frame();
- __ andcc(G4_scratch, sig_mask, G3_scratch);
- __ br(Assembler::zero, false, Assembler::pt, NonFloatArg);
- __ delayed()->nop();
-
- __ cmp(G3_scratch, float_sig );
- __ br(Assembler::equal, false, Assembler::pt, LoadFloatArg);
- __ delayed()->nop();
-
- __ cmp(G3_scratch, double_sig );
- __ br(Assembler::equal, false, Assembler::pt, LoadDoubleArg);
- __ delayed()->nop();
-
- __ bind(NonFloatArg);
- // There are only 6 integer register arguments!
- if ( ldarg.is_register() )
- __ ld_ptr(ldarg.address_in_frame(), ldarg.as_register());
- else {
- // Optimization, see if there are any more args and get out prior to checking
- // all 16 float registers. My guess is that this is rare.
- // If is_register is false, then we are done the first six integer args.
- __ br_null_short(G4_scratch, Assembler::pt, done);
- }
- __ ba(NextArg);
- __ delayed()->srl( G4_scratch, 2, G4_scratch );
-
- __ bind(LoadFloatArg);
- __ ldf( FloatRegisterImpl::S, a, ldarg.as_float_register(), 4);
- __ ba(NextArg);
- __ delayed()->srl( G4_scratch, 2, G4_scratch );
-
- __ bind(LoadDoubleArg);
- __ ldf( FloatRegisterImpl::D, a, ldarg.as_double_register() );
- __ ba(NextArg);
- __ delayed()->srl( G4_scratch, 2, G4_scratch );
-
- __ bind(NextArg);
- }
-
- __ bind(done);
- __ ret();
- __ delayed()->restore(O0, 0, Lscratch); // caller's Lscratch gets the result handler
-
- return entry;
-}
-
-void TemplateInterpreterGenerator::generate_counter_overflow(Label& Lcontinue) {
-
- // Generate code to initiate compilation on the counter overflow.
-
- // InterpreterRuntime::frequency_counter_overflow takes two arguments,
- // the first indicates if the counter overflow occurs at a backwards branch (NULL bcp)
- // and the second is only used when the first is true. We pass zero for both.
- // The call returns the address of the verified entry point for the method or NULL
- // if the compilation did not complete (either went background or bailed out).
- __ set((int)false, O2);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), O2, O2, true);
- // returns verified_entry_point or NULL
- // we ignore it in any case
- __ ba_short(Lcontinue);
-}
-
-
-// End of helpers
-
-// Various method entries
-
-// Abstract method entry
-// Attempt to execute abstract method. Throw exception
-//
-address TemplateInterpreterGenerator::generate_abstract_entry(void) {
- address entry = __ pc();
- // abstract method entry
- // throw exception
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodErrorWithMethod), G5_method);
- // the call_VM checks for exception, so we should never return here.
- __ should_not_reach_here();
- return entry;
-}
-
-void TemplateInterpreterGenerator::save_native_result(void) {
- // result potentially in O0/O1: save it across calls
- const Address& l_tmp = InterpreterMacroAssembler::l_tmp;
-
- // result potentially in F0/F1: save it across calls
- const Address& d_tmp = InterpreterMacroAssembler::d_tmp;
-
- // save and restore any potential method result value around the unlocking operation
- __ stf(FloatRegisterImpl::D, F0, d_tmp);
- __ stx(O0, l_tmp);
-}
-
-void TemplateInterpreterGenerator::restore_native_result(void) {
- const Address& l_tmp = InterpreterMacroAssembler::l_tmp;
- const Address& d_tmp = InterpreterMacroAssembler::d_tmp;
-
- // Restore any method result value
- __ ldf(FloatRegisterImpl::D, d_tmp, F0);
- __ ldx(l_tmp, O0);
-}
-
-address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
- assert(!pass_oop || message == NULL, "either oop or message but not both");
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- // load exception object
- __ set((intptr_t)name, G3_scratch);
- if (pass_oop) {
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), G3_scratch, Otos_i);
- } else {
- __ set((intptr_t)message, G4_scratch);
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), G3_scratch, G4_scratch);
- }
- // throw exception
- assert(Interpreter::throw_exception_entry() != NULL, "generate it first");
- AddressLiteral thrower(Interpreter::throw_exception_entry());
- __ jump_to(thrower, G3_scratch);
- __ delayed()->nop();
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception
- // happened
- __ empty_expression_stack();
- // load exception object
- __ call_VM(Oexception,
- CAST_FROM_FN_PTR(address,
- InterpreterRuntime::throw_ClassCastException),
- Otos_i);
- __ should_not_reach_here();
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- // Pass the array to create more detailed exceptions.
- // convention: expect aberrant index in register G3_scratch, then shuffle the
- // index to G4_scratch for the VM call
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), G3_scratch, Otos_i);
- __ should_not_reach_here();
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
- address entry = __ pc();
- // expression stack must be empty before entering the VM if an exception happened
- __ empty_expression_stack();
- __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError));
- __ should_not_reach_here();
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
- address entry = __ pc();
-
- if (state == atos) {
- __ profile_return_type(O0, G3_scratch, G1_scratch);
- }
-
- // The callee returns with the stack possibly adjusted by adapter transition
- // We remove that possible adjustment here.
- // All interpreter local registers are untouched. Any result is passed back
- // in the O0/O1 or float registers. Before continuing, the arguments must be
- // popped from the java expression stack; i.e., Lesp must be adjusted.
-
- __ mov(Llast_SP, SP); // Remove any adapter added stack space.
-
- const Register cache = G3_scratch;
- const Register index = G1_scratch;
- __ get_cache_and_index_at_bcp(cache, index, 1, index_size);
-
- const Register flags = cache;
- __ ld_ptr(cache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset(), flags);
- const Register parameter_size = flags;
- __ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, parameter_size); // argument size in words
- __ sll(parameter_size, Interpreter::logStackElementSize, parameter_size); // each argument size in bytes
- __ add(Lesp, parameter_size, Lesp); // pop arguments
-
- __ check_and_handle_popframe(Gtemp);
- __ check_and_handle_earlyret(Gtemp);
-
- __ dispatch_next(state, step);
-
- return entry;
-}
-
-
-address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step, address continuation) {
- address entry = __ pc();
- __ get_constant_pool_cache(LcpoolCache); // load LcpoolCache
-#if INCLUDE_JVMCI
- // Check if we need to take lock at entry of synchronized method. This can
- // only occur on method entry so emit it only for vtos with step 0.
- if (EnableJVMCI && state == vtos && step == 0) {
- Label L;
- Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset());
- __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter
- __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L);
- // Clear flag.
- __ stbool(G0, pending_monitor_enter_addr);
- // Take lock.
- lock_method();
- __ bind(L);
- } else {
-#ifdef ASSERT
- if (EnableJVMCI) {
- Label L;
- Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset());
- __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter
- __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L);
- __ stop("unexpected pending monitor in deopt entry");
- __ bind(L);
- }
-#endif
- }
-#endif
- { Label L;
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- __ ld_ptr(exception_addr, Gtemp); // Load pending exception.
- __ br_null_short(Gtemp, Assembler::pt, L);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
- if (continuation == NULL) {
- __ dispatch_next(state, step);
- } else {
- __ jump_to_entry(continuation);
- }
- return entry;
-}
-
-// A result handler converts/unboxes a native call result into
-// a java interpreter/compiler result. The current frame is an
-// interpreter frame. The activation frame unwind code must be
-// consistent with that of TemplateTable::_return(...). In the
-// case of native methods, the caller's SP was not modified.
-address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
- address entry = __ pc();
- Register Itos_i = Otos_i ->after_save();
- Register Itos_l = Otos_l ->after_save();
- Register Itos_l1 = Otos_l1->after_save();
- Register Itos_l2 = Otos_l2->after_save();
- switch (type) {
- case T_BOOLEAN: __ subcc(G0, O0, G0); __ addc(G0, 0, Itos_i); break; // !0 => true; 0 => false
- case T_CHAR : __ sll(O0, 16, O0); __ srl(O0, 16, Itos_i); break; // cannot use and3, 0xFFFF too big as immediate value!
- case T_BYTE : __ sll(O0, 24, O0); __ sra(O0, 24, Itos_i); break;
- case T_SHORT : __ sll(O0, 16, O0); __ sra(O0, 16, Itos_i); break;
- case T_LONG :
- case T_INT : __ mov(O0, Itos_i); break;
- case T_VOID : /* nothing to do */ break;
- case T_FLOAT : assert(F0 == Ftos_f, "fix this code" ); break;
- case T_DOUBLE : assert(F0 == Ftos_d, "fix this code" ); break;
- case T_OBJECT :
- __ ld_ptr(FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS, Itos_i);
- __ verify_oop(Itos_i);
- break;
- default : ShouldNotReachHere();
- }
- __ ret(); // return from interpreter activation
- __ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame
- NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly
- return entry;
-}
-
-address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
- address entry = __ pc();
- __ push(state);
- __ call_VM(noreg, runtime_entry);
- __ dispatch_via(vtos, Interpreter::normal_table(vtos));
- return entry;
-}
-
-
-//
-// Helpers for commoning out cases in the various type of method entries.
-//
-
-// increment invocation count & check for overflow
-//
-// Note: checking for negative value instead of overflow
-// so we have a 'sticky' overflow test
-//
-// Lmethod: method
-// ??: invocation counter
-//
-void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
- // Note: In tiered we increment either counters in MethodCounters* or in
- // MDO depending if we're profiling or not.
- const Register G3_method_counters = G3_scratch;
- Label done;
-
- if (TieredCompilation) {
- const int increment = InvocationCounter::count_increment;
- Label no_mdo;
- if (ProfileInterpreter) {
- // If no method data exists, go to profile_continue.
- __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch);
- __ br_null_short(G4_scratch, Assembler::pn, no_mdo);
- // Increment counter
- Address mdo_invocation_counter(G4_scratch,
- in_bytes(MethodData::invocation_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset()));
- __ increment_mask_and_jump(mdo_invocation_counter, increment, mask,
- G3_scratch, Lscratch,
- Assembler::zero, overflow);
- __ ba_short(done);
- }
-
- // Increment counter in MethodCounters*
- __ bind(no_mdo);
- Address invocation_counter(G3_method_counters,
- in_bytes(MethodCounters::invocation_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- __ get_method_counters(Lmethod, G3_method_counters, done);
- Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset()));
- __ increment_mask_and_jump(invocation_counter, increment, mask,
- G4_scratch, Lscratch,
- Assembler::zero, overflow);
- __ bind(done);
- } else { // not TieredCompilation
- // Update standard invocation counters
- __ get_method_counters(Lmethod, G3_method_counters, done);
- __ increment_invocation_counter(G3_method_counters, O0, G4_scratch);
- if (ProfileInterpreter) {
- Address interpreter_invocation_counter(G3_method_counters,
- in_bytes(MethodCounters::interpreter_invocation_counter_offset()));
- __ ld(interpreter_invocation_counter, G4_scratch);
- __ inc(G4_scratch);
- __ st(G4_scratch, interpreter_invocation_counter);
- }
-
- if (ProfileInterpreter && profile_method != NULL) {
- // Test to see if we should create a method data oop
- Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset()));
- __ ld(profile_limit, G1_scratch);
- __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue);
-
- // if no method data exists, go to profile_method
- __ test_method_data_pointer(*profile_method);
- }
-
- Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset()));
- __ ld(invocation_limit, G3_scratch);
- __ cmp(O0, G3_scratch);
- __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance
- __ delayed()->nop();
- __ bind(done);
- }
-}
-
-// Allocate monitor and lock method (asm interpreter)
-// ebx - Method*
-//
-void TemplateInterpreterGenerator::lock_method() {
- __ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags.
-
-#ifdef ASSERT
- { Label ok;
- __ btst(JVM_ACC_SYNCHRONIZED, O0);
- __ br( Assembler::notZero, false, Assembler::pt, ok);
- __ delayed()->nop();
- __ stop("method doesn't need synchronization");
- __ bind(ok);
- }
-#endif // ASSERT
-
- // get synchronization object to O0
- { Label done;
- __ btst(JVM_ACC_STATIC, O0);
- __ br( Assembler::zero, true, Assembler::pt, done);
- __ delayed()->ld_ptr(Llocals, Interpreter::local_offset_in_bytes(0), O0); // get receiver for not-static case
-
- // lock the mirror, not the Klass*
- __ load_mirror(O0, Lmethod, Lscratch);
-
-#ifdef ASSERT
- __ tst(O0);
- __ breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
-#endif // ASSERT
-
- __ bind(done);
- }
-
- __ add_monitor_to_stack(true, noreg, noreg); // allocate monitor elem
- __ st_ptr( O0, Lmonitors, BasicObjectLock::obj_offset_in_bytes()); // store object
- // __ untested("lock_object from method entry");
- __ lock_object(Lmonitors, O0);
-}
-
-// See if we've got enough room on the stack for locals plus overhead below
-// JavaThread::stack_overflow_limit(). If not, throw a StackOverflowError
-// without going through the signal handler, i.e., reserved and yellow zones
-// will not be made usable. The shadow zone must suffice to handle the
-// overflow.
-void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rframe_size,
- Register Rscratch) {
- const int page_size = os::vm_page_size();
- Label after_frame_check;
-
- assert_different_registers(Rframe_size, Rscratch);
-
- __ set(page_size, Rscratch);
- __ cmp_and_br_short(Rframe_size, Rscratch, Assembler::lessEqual, Assembler::pt, after_frame_check);
-
- // Get the stack overflow limit, and in debug, verify it is non-zero.
- __ ld_ptr(G2_thread, JavaThread::stack_overflow_limit_offset(), Rscratch);
-#ifdef ASSERT
- Label limit_ok;
- __ br_notnull_short(Rscratch, Assembler::pn, limit_ok);
- __ stop("stack overflow limit is zero in generate_stack_overflow_check");
- __ bind(limit_ok);
-#endif
-
- // Add in the size of the frame (which is the same as subtracting it from the
- // SP, which would take another register.
- __ add(Rscratch, Rframe_size, Rscratch);
-
- // The frame is greater than one page in size, so check against
- // the bottom of the stack.
- __ cmp_and_brx_short(SP, Rscratch, Assembler::greaterUnsigned, Assembler::pt, after_frame_check);
-
- // The stack will overflow, throw an exception.
-
- // Note that SP is restored to sender's sp (in the delay slot). This
- // is necessary if the sender's frame is an extended compiled frame
- // (see gen_c2i_adapter()) and safer anyway in case of JSR292
- // adaptations.
-
- // Note also that the restored frame is not necessarily interpreted.
- // Use the shared runtime version of the StackOverflowError.
- assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated");
- AddressLiteral stub(StubRoutines::throw_StackOverflowError_entry());
- __ jump_to(stub, Rscratch);
- __ delayed()->mov(O5_savedSP, SP);
-
- // If you get to here, then there is enough stack space.
- __ bind(after_frame_check);
-}
-
-
-//
-// Generate a fixed interpreter frame. This is identical setup for interpreted
-// methods and for native methods hence the shared code.
-
-
-//----------------------------------------------------------------------------------------------------
-// Stack frame layout
-//
-// When control flow reaches any of the entry types for the interpreter
-// the following holds ->
-//
-// C2 Calling Conventions:
-//
-// The entry code below assumes that the following registers are set
-// when coming in:
-// G5_method: holds the Method* of the method to call
-// Lesp: points to the TOS of the callers expression stack
-// after having pushed all the parameters
-//
-// The entry code does the following to setup an interpreter frame
-// pop parameters from the callers stack by adjusting Lesp
-// set O0 to Lesp
-// compute X = (max_locals - num_parameters)
-// bump SP up by X to accommodate the extra locals
-// compute X = max_expression_stack
-// + vm_local_words
-// + 16 words of register save area
-// save frame doing a save sp, -X, sp growing towards lower addresses
-// set Lbcp, Lmethod, LcpoolCache
-// set Llocals to i0
-// set Lmonitors to FP - rounded_vm_local_words
-// set Lesp to Lmonitors - 4
-//
-// The frame has now been setup to do the rest of the entry code
-
-// Try this optimization: Most method entries could live in a
-// "one size fits all" stack frame without all the dynamic size
-// calculations. It might be profitable to do all this calculation
-// statically and approximately for "small enough" methods.
-
-//-----------------------------------------------------------------------------------------------
-
-// C1 Calling conventions
-//
-// Upon method entry, the following registers are setup:
-//
-// g2 G2_thread: current thread
-// g5 G5_method: method to activate
-// g4 Gargs : pointer to last argument
-//
-//
-// Stack:
-//
-// +---------------+ <--- sp
-// | |
-// : reg save area :
-// | |
-// +---------------+ <--- sp + 0x40
-// | |
-// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
-// | |
-// +---------------+ <--- sp + 0x5c
-// | |
-// : free :
-// | |
-// +---------------+ <--- Gargs
-// | |
-// : arguments :
-// | |
-// +---------------+
-// | |
-//
-//
-//
-// AFTER FRAME HAS BEEN SETUP for method interpretation the stack looks like:
-//
-// +---------------+ <--- sp
-// | |
-// : reg save area :
-// | |
-// +---------------+ <--- sp + 0x40
-// | |
-// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
-// | |
-// +---------------+ <--- sp + 0x5c
-// | |
-// : :
-// | | <--- Lesp
-// +---------------+ <--- Lmonitors (fp - 0x18)
-// | VM locals |
-// +---------------+ <--- fp
-// | |
-// : reg save area :
-// | |
-// +---------------+ <--- fp + 0x40
-// | |
-// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later)
-// | |
-// +---------------+ <--- fp + 0x5c
-// | |
-// : free :
-// | |
-// +---------------+
-// | |
-// : nonarg locals :
-// | |
-// +---------------+
-// | |
-// : arguments :
-// | | <--- Llocals
-// +---------------+ <--- Gargs
-// | |
-
-void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
- //
- //
- // The entry code sets up a new interpreter frame in 4 steps:
- //
- // 1) Increase caller's SP by for the extra local space needed:
- // (check for overflow)
- // Efficient implementation of xload/xstore bytecodes requires
- // that arguments and non-argument locals are in a contiguously
- // addressable memory block => non-argument locals must be
- // allocated in the caller's frame.
- //
- // 2) Create a new stack frame and register window:
- // The new stack frame must provide space for the standard
- // register save area, the maximum java expression stack size,
- // the monitor slots (0 slots initially), and some frame local
- // scratch locations.
- //
- // 3) The following interpreter activation registers must be setup:
- // Lesp : expression stack pointer
- // Lbcp : bytecode pointer
- // Lmethod : method
- // Llocals : locals pointer
- // Lmonitors : monitor pointer
- // LcpoolCache: constant pool cache
- //
- // 4) Initialize the non-argument locals if necessary:
- // Non-argument locals may need to be initialized to NULL
- // for GC to work. If the oop-map information is accurate
- // (in the absence of the JSR problem), no initialization
- // is necessary.
- //
- // (gri - 2/25/2000)
-
-
- int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words, WordsPerLong );
-
- const int extra_space =
- rounded_vm_local_words + // frame local scratch space
- Method::extra_stack_entries() + // extra stack for jsr 292
- frame::memory_parameter_word_sp_offset + // register save area
- (native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
-
- const Register Glocals_size = G3;
- const Register RconstMethod = Glocals_size;
- const Register Otmp1 = O3;
- const Register Otmp2 = O4;
- // Lscratch can't be used as a temporary because the call_stub uses
- // it to assert that the stack frame was setup correctly.
- const Address constMethod (G5_method, Method::const_offset());
- const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
-
- __ ld_ptr( constMethod, RconstMethod );
- __ lduh( size_of_parameters, Glocals_size);
-
- // Gargs points to first local + BytesPerWord
- // Set the saved SP after the register window save
- //
- assert_different_registers(Gargs, Glocals_size, Gframe_size, O5_savedSP);
- __ sll(Glocals_size, Interpreter::logStackElementSize, Otmp1);
- __ add(Gargs, Otmp1, Gargs);
-
- if (native_call) {
- __ calc_mem_param_words( Glocals_size, Gframe_size );
- __ add( Gframe_size, extra_space, Gframe_size);
- __ round_to( Gframe_size, WordsPerLong );
- __ sll( Gframe_size, LogBytesPerWord, Gframe_size );
-
- // Native calls don't need the stack size check since they have no
- // expression stack and the arguments are already on the stack and
- // we only add a handful of words to the stack.
- } else {
-
- //
- // Compute number of locals in method apart from incoming parameters
- //
- const Address size_of_locals(Otmp1, ConstMethod::size_of_locals_offset());
- __ ld_ptr(constMethod, Otmp1);
- __ lduh(size_of_locals, Otmp1);
- __ sub(Otmp1, Glocals_size, Glocals_size);
- __ round_to(Glocals_size, WordsPerLong);
- __ sll(Glocals_size, Interpreter::logStackElementSize, Glocals_size);
-
- // See if the frame is greater than one page in size. If so,
- // then we need to verify there is enough stack space remaining.
- // Frame_size = (max_stack + extra_space) * BytesPerWord;
- __ ld_ptr(constMethod, Gframe_size);
- __ lduh(Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size);
- __ add(Gframe_size, extra_space, Gframe_size);
- __ round_to(Gframe_size, WordsPerLong);
- __ sll(Gframe_size, Interpreter::logStackElementSize, Gframe_size);
-
- // Add in java locals size for stack overflow check only
- __ add(Gframe_size, Glocals_size, Gframe_size);
-
- const Register Otmp2 = O4;
- assert_different_registers(Otmp1, Otmp2, O5_savedSP);
- generate_stack_overflow_check(Gframe_size, Otmp1);
-
- __ sub(Gframe_size, Glocals_size, Gframe_size);
-
- //
- // bump SP to accommodate the extra locals
- //
- __ sub(SP, Glocals_size, SP);
- }
-
- //
- // now set up a stack frame with the size computed above
- //
- __ neg( Gframe_size );
- __ save( SP, Gframe_size, SP );
-
- //
- // now set up all the local cache registers
- //
- // NOTE: At this point, Lbyte_code/Lscratch has been modified. Note
- // that all present references to Lbyte_code initialize the register
- // immediately before use
- if (native_call) {
- __ mov(G0, Lbcp);
- } else {
- __ ld_ptr(G5_method, Method::const_offset(), Lbcp);
- __ add(Lbcp, in_bytes(ConstMethod::codes_offset()), Lbcp);
- }
- __ mov( G5_method, Lmethod); // set Lmethod
- // Get mirror and store it in the frame as GC root for this Method*
- Register mirror = LcpoolCache;
- __ load_mirror(mirror, Lmethod, Lscratch);
- __ st_ptr(mirror, FP, (frame::interpreter_frame_mirror_offset * wordSize) + STACK_BIAS);
- __ get_constant_pool_cache(LcpoolCache); // set LcpoolCache
- __ sub(FP, rounded_vm_local_words * BytesPerWord, Lmonitors ); // set Lmonitors
- __ add(Lmonitors, STACK_BIAS, Lmonitors); // Account for 64 bit stack bias
- __ sub(Lmonitors, BytesPerWord, Lesp); // set Lesp
-
- // setup interpreter activation registers
- __ sub(Gargs, BytesPerWord, Llocals); // set Llocals
-
- if (ProfileInterpreter) {
- __ set_method_data_pointer();
- }
-
-}
-
-// Method entry for java.lang.ref.Reference.get.
-address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
- // Code: _aload_0, _getfield, _areturn
- // parameter size = 1
- //
- // The code that gets generated by this routine is split into 2 parts:
- // 1. The "intrinsified" code performing an ON_WEAK_OOP_REF load,
- // 2. The slow path - which is an expansion of the regular method entry.
- //
- // Notes:-
- // * An intrinsic is always executed, where an ON_WEAK_OOP_REF load is performed.
- // * We may jump to the slow path iff the receiver is null. If the
- // Reference object is null then we no longer perform an ON_WEAK_OOP_REF load
- // Thus we can use the regular method entry code to generate the NPE.
- //
- // This code is based on generate_accessor_enty.
-
- address entry = __ pc();
-
- const int referent_offset = java_lang_ref_Reference::referent_offset;
- guarantee(referent_offset > 0, "referent offset not initialized");
-
- Label slow_path;
-
- // In the G1 code we don't check if we need to reach a safepoint. We
- // continue and the thread will safepoint at the next bytecode dispatch.
-
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ ld_ptr(Gargs, G0, Otos_i ); // get local 0
- // check if local 0 == NULL and go the slow path
- __ cmp_and_brx_short(Otos_i, 0, Assembler::equal, Assembler::pn, slow_path);
-
- __ load_heap_oop(Otos_i, referent_offset, Otos_i, G3_scratch, ON_WEAK_OOP_REF);
-
- // _areturn
- __ retl(); // return from leaf routine
- __ delayed()->mov(O5_savedSP, SP);
-
- // Generate regular method entry
- __ bind(slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
- return entry;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.update(int crc, int b)
- */
-address TemplateInterpreterGenerator::generate_CRC32_update_entry() {
-
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- Label L_slow_path;
- // If we need a safepoint check, generate full interpreter entry.
- __ safepoint_poll(L_slow_path, false, G2_thread, O2);
- __ delayed()->nop();
-
- // Load parameters
- const Register crc = O0; // initial crc
- const Register val = O1; // byte to update with
- const Register table = O2; // address of 256-entry lookup table
-
- __ ldub(Gargs, 3, val);
- __ lduw(Gargs, 8, crc);
-
- __ set(ExternalAddress(StubRoutines::crc_table_addr()), table);
-
- __ not1(crc); // ~crc
- __ clruwu(crc);
- __ update_byte_crc32(crc, val, table);
- __ not1(crc); // ~crc
-
- // result in O0
- __ retl();
- __ delayed()->nop();
-
- // generate a vanilla native entry as the slow path
- __ bind(L_slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native));
- return entry;
- }
- return NULL;
-}
-
-/**
- * Method entry for static native methods:
- * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len)
- * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len)
- */
-address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
-
- if (UseCRC32Intrinsics) {
- address entry = __ pc();
-
- Label L_slow_path;
- // If we need a safepoint check, generate full interpreter entry.
-
- __ safepoint_poll(L_slow_path, false, G2_thread, O2);
- __ delayed()->nop();
-
- // Load parameters from the stack
- const Register crc = O0; // initial crc
- const Register buf = O1; // source java byte array address
- const Register len = O2; // len
- const Register offset = O3; // offset
-
- // Arguments are reversed on java expression stack
- // Calculate address of start element
- if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
- __ lduw(Gargs, 0, len);
- __ lduw(Gargs, 8, offset);
- __ ldx( Gargs, 16, buf);
- __ lduw(Gargs, 32, crc);
- __ add(buf, offset, buf);
- } else {
- __ lduw(Gargs, 0, len);
- __ lduw(Gargs, 8, offset);
- __ ldx( Gargs, 16, buf);
- __ lduw(Gargs, 24, crc);
- __ add(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // account for the header size
- __ add(buf, offset, buf);
- }
-
- // Call the crc32 kernel
- __ MacroAssembler::save_thread(L7_thread_cache);
- __ kernel_crc32(crc, buf, len, O3);
- __ MacroAssembler::restore_thread(L7_thread_cache);
-
- // result in O0
- __ retl();
- __ delayed()->nop();
-
- // generate a vanilla native entry as the slow path
- __ bind(L_slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native));
- return entry;
- }
- return NULL;
-}
-
-/**
- * Method entry for intrinsic-candidate (non-native) methods:
- * int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end)
- * int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long buf, int off, int end)
- * Unlike CRC32, CRC32C does not have any methods marked as native
- * CRC32C also uses an "end" variable instead of the length variable CRC32 uses
- */
-address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) {
-
- if (UseCRC32CIntrinsics) {
- address entry = __ pc();
-
- // Load parameters from the stack
- const Register crc = O0; // initial crc
- const Register buf = O1; // source java byte array address
- const Register offset = O2; // offset
- const Register end = O3; // index of last element to process
- const Register len = O2; // len argument to the kernel
- const Register table = O3; // crc32c lookup table address
-
- // Arguments are reversed on java expression stack
- // Calculate address of start element
- if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) {
- __ lduw(Gargs, 0, end);
- __ lduw(Gargs, 8, offset);
- __ ldx( Gargs, 16, buf);
- __ lduw(Gargs, 32, crc);
- __ add(buf, offset, buf);
- __ sub(end, offset, len);
- } else {
- __ lduw(Gargs, 0, end);
- __ lduw(Gargs, 8, offset);
- __ ldx( Gargs, 16, buf);
- __ lduw(Gargs, 24, crc);
- __ add(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // account for the header size
- __ add(buf, offset, buf);
- __ sub(end, offset, len);
- }
-
- // Call the crc32c kernel
- __ MacroAssembler::save_thread(L7_thread_cache);
- __ kernel_crc32c(crc, buf, len, table);
- __ MacroAssembler::restore_thread(L7_thread_cache);
-
- // result in O0
- __ retl();
- __ delayed()->nop();
-
- return entry;
- }
- return NULL;
-}
-
-/* Math routines only partially supported.
- *
- * Providing support for fma (float/double) only.
- */
-address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind)
-{
- if (!InlineIntrinsics) return NULL; // Generate a vanilla entry
-
- address entry = __ pc();
-
- switch (kind) {
- case Interpreter::java_lang_math_fmaF:
- if (UseFMA) {
- // float .fma(float a, float b, float c)
- const FloatRegister ra = F1;
- const FloatRegister rb = F2;
- const FloatRegister rc = F3;
- const FloatRegister rd = F0; // Result.
-
- __ ldf(FloatRegisterImpl::S, Gargs, 0, rc);
- __ ldf(FloatRegisterImpl::S, Gargs, 8, rb);
- __ ldf(FloatRegisterImpl::S, Gargs, 16, ra);
-
- __ fmadd(FloatRegisterImpl::S, ra, rb, rc, rd);
- __ retl(); // Result in F0 (rd).
- __ delayed()->mov(O5_savedSP, SP);
-
- return entry;
- }
- break;
- case Interpreter::java_lang_math_fmaD:
- if (UseFMA) {
- // double .fma(double a, double b, double c)
- const FloatRegister ra = F2; // D1
- const FloatRegister rb = F4; // D2
- const FloatRegister rc = F6; // D3
- const FloatRegister rd = F0; // D0 Result.
-
- __ ldf(FloatRegisterImpl::D, Gargs, 0, rc);
- __ ldf(FloatRegisterImpl::D, Gargs, 16, rb);
- __ ldf(FloatRegisterImpl::D, Gargs, 32, ra);
-
- __ fmadd(FloatRegisterImpl::D, ra, rb, rc, rd);
- __ retl(); // Result in D0 (rd).
- __ delayed()->mov(O5_savedSP, SP);
-
- return entry;
- }
- break;
- default:
- break;
- }
- return NULL;
-}
-
-// TODO: rather than touching all pages, check against stack_overflow_limit and bang yellow page to
-// generate exception
-void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) {
- // Quick & dirty stack overflow checking: bang the stack & handle trap.
- // Note that we do the banging after the frame is setup, since the exception
- // handling code expects to find a valid interpreter frame on the stack.
- // Doing the banging earlier fails if the caller frame is not an interpreter
- // frame.
- // (Also, the exception throwing code expects to unlock any synchronized
- // method receiver, so do the banging after locking the receiver.)
-
- // Bang each page in the shadow zone. We can't assume it's been done for
- // an interpreter frame with greater than a page of locals, so each page
- // needs to be checked. Only true for non-native.
- if (UseStackBanging) {
- const int page_size = os::vm_page_size();
- const int n_shadow_pages = ((int)JavaThread::stack_shadow_zone_size()) / page_size;
- const int start_page = native_call ? n_shadow_pages : 1;
- for (int pages = start_page; pages <= n_shadow_pages; pages++) {
- __ bang_stack_with_offset(pages*page_size);
- }
- }
-}
-
-//
-// Interpreter stub for calling a native method. (asm interpreter)
-// This sets up a somewhat different looking stack for calling the native method
-// than the typical interpreter frame setup.
-//
-
-address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
- address entry = __ pc();
-
- // the following temporary registers are used during frame creation
- const Register Gtmp1 = G3_scratch ;
- const Register Gtmp2 = G1_scratch;
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // make sure registers are different!
- assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
-
- const Address Laccess_flags(Lmethod, Method::access_flags_offset());
-
- const Register Glocals_size = G3;
- assert_different_registers(Glocals_size, G4_scratch, Gframe_size);
-
- // make sure method is native & not abstract
- // rethink these assertions - they can be simplified and shared (gri 2/25/2000)
-#ifdef ASSERT
- __ ld(G5_method, Method::access_flags_offset(), Gtmp1);
- { Label L;
- __ btst(JVM_ACC_NATIVE, Gtmp1);
- __ br(Assembler::notZero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute non-native method as native");
- __ bind(L);
- }
- { Label L;
- __ btst(JVM_ACC_ABSTRACT, Gtmp1);
- __ br(Assembler::zero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute abstract method as non-abstract");
- __ bind(L);
- }
-#endif // ASSERT
-
- // generate the code to allocate the interpreter stack frame
- generate_fixed_frame(true);
-
- //
- // No locals to initialize for native method
- //
-
- // this slot will be set later, we initialize it to null here just in
- // case we get a GC before the actual value is stored later
- __ st_ptr(G0, FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS);
-
- const Address do_not_unlock_if_synchronized(G2_thread,
- JavaThread::do_not_unlock_if_synchronized_offset());
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. If any exception was thrown by
- // runtime, exception handling i.e. unlock_if_synchronized_method will
- // check this thread local flag.
- // This flag has two effects, one is to force an unwind in the topmost
- // interpreter frame and not perform an unlock while doing so.
-
- __ movbool(true, G3_scratch);
- __ stbool(G3_scratch, do_not_unlock_if_synchronized);
-
- // increment invocation counter and check for overflow
- //
- // Note: checking for negative value instead of overflow
- // so we have a 'sticky' overflow test (may be of
- // importance as soon as we have true MT/MP)
- Label invocation_counter_overflow;
- Label Lcontinue;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
-
- }
- __ bind(Lcontinue);
-
- bang_stack_shadow_pages(true);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ stbool(G0, do_not_unlock_if_synchronized);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
-
- if (synchronized) {
- lock_method();
- } else {
-#ifdef ASSERT
- { Label ok;
- __ ld(Laccess_flags, O0);
- __ btst(JVM_ACC_SYNCHRONIZED, O0);
- __ br( Assembler::zero, false, Assembler::pt, ok);
- __ delayed()->nop();
- __ stop("method needs synchronization");
- __ bind(ok);
- }
-#endif // ASSERT
- }
-
-
- // start execution
- __ verify_thread();
-
- // JVMTI support
- __ notify_method_entry();
-
- // native call
-
- // (note that O0 is never an oop--at most it is a handle)
- // It is important not to smash any handles created by this call,
- // until any oop handle in O0 is dereferenced.
-
- // (note that the space for outgoing params is preallocated)
-
- // get signature handler
- { Label L;
- Address signature_handler(Lmethod, Method::signature_handler_offset());
- __ ld_ptr(signature_handler, G3_scratch);
- __ br_notnull_short(G3_scratch, Assembler::pt, L);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), Lmethod);
- __ ld_ptr(signature_handler, G3_scratch);
- __ bind(L);
- }
-
- // Push a new frame so that the args will really be stored in
- // Copy a few locals across so the new frame has the variables
- // we need but these values will be dead at the jni call and
- // therefore not gc volatile like the values in the current
- // frame (Lmethod in particular)
-
- // Flush the method pointer to the register save area
- __ st_ptr(Lmethod, SP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS);
- __ mov(Llocals, O1);
-
- // calculate where the mirror handle body is allocated in the interpreter frame:
- __ add(FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS, O2);
-
- // Calculate current frame size
- __ sub(SP, FP, O3); // Calculate negative of current frame size
- __ save(SP, O3, SP); // Allocate an identical sized frame
-
- // Note I7 has leftover trash. Slow signature handler will fill it in
- // should we get there. Normal jni call will set reasonable last_Java_pc
- // below (and fix I7 so the stack trace doesn't have a meaningless frame
- // in it).
-
- // Load interpreter frame's Lmethod into same register here
-
- __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod);
-
- __ mov(I1, Llocals);
- __ mov(I2, Lscratch2); // save the address of the mirror
-
-
- // ONLY Lmethod and Llocals are valid here!
-
- // call signature handler, It will move the arg properly since Llocals in current frame
- // matches that in outer frame
-
- __ callr(G3_scratch, 0);
- __ delayed()->nop();
-
- // Result handler is in Lscratch
-
- // Reload interpreter frame's Lmethod since slow signature handler may block
- __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod);
-
- { Label not_static;
-
- __ ld(Laccess_flags, O0);
- __ btst(JVM_ACC_STATIC, O0);
- __ br( Assembler::zero, false, Assembler::pt, not_static);
- // get native function entry point(O0 is a good temp until the very end)
- __ delayed()->ld_ptr(Lmethod, in_bytes(Method::native_function_offset()), O0);
- // for static methods insert the mirror argument
- __ load_mirror(O1, Lmethod, G3_scratch);
-#ifdef ASSERT
- if (!PrintSignatureHandlers) // do not dirty the output with this
- { Label L;
- __ br_notnull_short(O1, Assembler::pt, L);
- __ stop("mirror is missing");
- __ bind(L);
- }
-#endif // ASSERT
- __ st_ptr(O1, Lscratch2, 0);
- __ mov(Lscratch2, O1);
- __ bind(not_static);
- }
-
- // At this point, arguments have been copied off of stack into
- // their JNI positions, which are O1..O5 and SP[68..].
- // Oops are boxed in-place on the stack, with handles copied to arguments.
- // The result handler is in Lscratch. O0 will shortly hold the JNIEnv*.
-
-#ifdef ASSERT
- { Label L;
- __ br_notnull_short(O0, Assembler::pt, L);
- __ stop("native entry point is missing");
- __ bind(L);
- }
-#endif // ASSERT
-
- //
- // setup the frame anchor
- //
- // The scavenge function only needs to know that the PC of this frame is
- // in the interpreter method entry code, it doesn't need to know the exact
- // PC and hence we can use O7 which points to the return address from the
- // previous call in the code stream (signature handler function)
- //
- // The other trick is we set last_Java_sp to FP instead of the usual SP because
- // we have pushed the extra frame in order to protect the volatile register(s)
- // in that frame when we return from the jni call
- //
-
- __ set_last_Java_frame(FP, O7);
- __ mov(O7, I7); // make dummy interpreter frame look like one above,
- // not meaningless information that'll confuse me.
-
- // flush the windows now. We don't care about the current (protection) frame
- // only the outer frames
-
- __ flushw();
-
- // mark windows as flushed
- Address flags(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset());
- __ set(JavaFrameAnchor::flushed, G3_scratch);
- __ st(G3_scratch, flags);
-
- // Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready.
-
- Address thread_state(G2_thread, JavaThread::thread_state_offset());
-#ifdef ASSERT
- { Label L;
- __ ld(thread_state, G3_scratch);
- __ cmp_and_br_short(G3_scratch, _thread_in_Java, Assembler::equal, Assembler::pt, L);
- __ stop("Wrong thread state in native stub");
- __ bind(L);
- }
-#endif // ASSERT
- __ set(_thread_in_native, G3_scratch);
- __ st(G3_scratch, thread_state);
-
- // Call the jni method, using the delay slot to set the JNIEnv* argument.
- __ save_thread(L7_thread_cache); // save Gthread
- __ callr(O0, 0);
- __ delayed()->
- add(L7_thread_cache, in_bytes(JavaThread::jni_environment_offset()), O0);
-
- // Back from jni method Lmethod in this frame is DEAD, DEAD, DEAD
-
- __ restore_thread(L7_thread_cache); // restore G2_thread
- __ reinit_heapbase();
-
- // must we block?
-
- // Block, if necessary, before resuming in _thread_in_Java state.
- // In order for GC to work, don't clear the last_Java_sp until after blocking.
- { Label no_block;
-
- // Switch thread to "native transition" state before reading the synchronization state.
- // This additional state is necessary because reading and testing the synchronization
- // state is not atomic w.r.t. GC, as this scenario demonstrates:
- // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted.
- // VM thread changes sync state to synchronizing and suspends threads for GC.
- // Thread A is resumed to finish this native method, but doesn't block here since it
- // didn't see any synchronization is progress, and escapes.
- __ set(_thread_in_native_trans, G3_scratch);
- __ st(G3_scratch, thread_state);
-
- // Force this write out before the read below
- __ membar(Assembler::StoreLoad);
-
- Label L;
- __ safepoint_poll(L, false, G2_thread, G3_scratch);
- __ delayed()->ld(G2_thread, JavaThread::suspend_flags_offset(), G3_scratch);
- __ cmp_and_br_short(G3_scratch, 0, Assembler::equal, Assembler::pt, no_block);
- __ bind(L);
-
- // Block. Save any potential method result value before the operation and
- // use a leaf call to leave the last_Java_frame setup undisturbed.
- save_native_result();
- __ call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
- G2_thread);
-
- // Restore any method result value
- restore_native_result();
- __ bind(no_block);
- }
-
- // Clear the frame anchor now
-
- __ reset_last_Java_frame();
-
- // Move the result handler address
- __ mov(Lscratch, G3_scratch);
- // return possible result to the outer frame
- __ restore(O0, G0, O0);
-
- // Move result handler to expected register
- __ mov(G3_scratch, Lscratch);
-
- // Back in normal (native) interpreter frame. State is thread_in_native_trans
- // switch to thread_in_Java.
-
- __ set(_thread_in_Java, G3_scratch);
- __ st(G3_scratch, thread_state);
-
- if (CheckJNICalls) {
- // clear_pending_jni_exception_check
- __ st_ptr(G0, G2_thread, JavaThread::pending_jni_exception_check_fn_offset());
- }
-
- // reset handle block
- __ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch);
- __ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
-
- // If we have an oop result store it where it will be safe for any further gc
- // until we return now that we've released the handle it might be protected by
-
- { Label no_oop;
-
- __ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch);
- __ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop);
- __ resolve_jobject(O0, G3_scratch);
- // Store it where gc will look for it and result handler expects it.
- __ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS);
-
- __ bind(no_oop);
- }
-
-
- // handle exceptions (exception handling will handle unlocking!)
- { Label L;
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- __ ld_ptr(exception_addr, Gtemp);
- __ br_null_short(Gtemp, Assembler::pt, L);
- // Note: This could be handled more efficiently since we know that the native
- // method doesn't have an exception handler. We could directly return
- // to the exception handler for the caller.
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception));
- __ should_not_reach_here();
- __ bind(L);
- }
-
- // JVMTI support (preserves thread register)
- __ notify_method_exit(true, ilgl, InterpreterMacroAssembler::NotifyJVMTI);
-
- if (synchronized) {
- // save and restore any potential method result value around the unlocking operation
- save_native_result();
-
- __ add( __ top_most_monitor(), O1);
- __ unlock_object(O1);
-
- restore_native_result();
- }
-
- // dispose of return address and remove activation
-#ifdef ASSERT
- { Label ok;
- __ cmp_and_brx_short(I5_savedSP, FP, Assembler::greaterEqualUnsigned, Assembler::pt, ok);
- __ stop("bad I5_savedSP value");
- __ should_not_reach_here();
- __ bind(ok);
- }
-#endif
- __ jmp(Lscratch, 0);
- __ delayed()->nop();
-
- if (inc_counter) {
- // handle invocation counter overflow
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(Lcontinue);
- }
-
- return entry;
-}
-
-
-// Generic method entry to (asm) interpreter
-address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
- address entry = __ pc();
-
- bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
-
- // the following temporary registers are used during frame creation
- const Register Gtmp1 = G3_scratch ;
- const Register Gtmp2 = G1_scratch;
-
- // make sure registers are different!
- assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
-
- const Address constMethod (G5_method, Method::const_offset());
- // Seems like G5_method is live at the point this is used. So we could make this look consistent
- // and use in the asserts.
- const Address access_flags (Lmethod, Method::access_flags_offset());
-
- const Register Glocals_size = G3;
- assert_different_registers(Glocals_size, G4_scratch, Gframe_size);
-
- // make sure method is not native & not abstract
- // rethink these assertions - they can be simplified and shared (gri 2/25/2000)
-#ifdef ASSERT
- __ ld(G5_method, Method::access_flags_offset(), Gtmp1);
- { Label L;
- __ btst(JVM_ACC_NATIVE, Gtmp1);
- __ br(Assembler::zero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute native method as non-native");
- __ bind(L);
- }
- { Label L;
- __ btst(JVM_ACC_ABSTRACT, Gtmp1);
- __ br(Assembler::zero, false, Assembler::pt, L);
- __ delayed()->nop();
- __ stop("tried to execute abstract method as non-abstract");
- __ bind(L);
- }
-#endif // ASSERT
-
- // generate the code to allocate the interpreter stack frame
-
- generate_fixed_frame(false);
-
- //
- // Code to initialize the extra (i.e. non-parm) locals
- //
- Register init_value = noreg; // will be G0 if we must clear locals
- // The way the code was setup before zerolocals was always true for vanilla java entries.
- // It could only be false for the specialized entries like accessor or empty which have
- // no extra locals so the testing was a waste of time and the extra locals were always
- // initialized. We removed this extra complication to already over complicated code.
-
- init_value = G0;
- Label clear_loop;
-
- const Register RconstMethod = O1;
- const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
- const Address size_of_locals (RconstMethod, ConstMethod::size_of_locals_offset());
-
- // NOTE: If you change the frame layout, this code will need to
- // be updated!
- __ ld_ptr( constMethod, RconstMethod );
- __ lduh( size_of_locals, O2 );
- __ lduh( size_of_parameters, O1 );
- __ sll( O2, Interpreter::logStackElementSize, O2);
- __ sll( O1, Interpreter::logStackElementSize, O1 );
- __ sub( Llocals, O2, O2 );
- __ sub( Llocals, O1, O1 );
-
- __ bind( clear_loop );
- __ inc( O2, wordSize );
-
- __ cmp( O2, O1 );
- __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, clear_loop );
- __ delayed()->st_ptr( init_value, O2, 0 );
-
- const Address do_not_unlock_if_synchronized(G2_thread,
- JavaThread::do_not_unlock_if_synchronized_offset());
- // Since at this point in the method invocation the exception handler
- // would try to exit the monitor of synchronized methods which hasn't
- // been entered yet, we set the thread local variable
- // _do_not_unlock_if_synchronized to true. If any exception was thrown by
- // runtime, exception handling i.e. unlock_if_synchronized_method will
- // check this thread local flag.
- __ movbool(true, G3_scratch);
- __ stbool(G3_scratch, do_not_unlock_if_synchronized);
-
- __ profile_parameters_type(G1_scratch, G3_scratch, G4_scratch, Lscratch);
- // increment invocation counter and check for overflow
- //
- // Note: checking for negative value instead of overflow
- // so we have a 'sticky' overflow test (may be of
- // importance as soon as we have true MT/MP)
- Label invocation_counter_overflow;
- Label profile_method;
- Label profile_method_continue;
- Label Lcontinue;
- if (inc_counter) {
- generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
- if (ProfileInterpreter) {
- __ bind(profile_method_continue);
- }
- }
- __ bind(Lcontinue);
-
- bang_stack_shadow_pages(false);
-
- // reset the _do_not_unlock_if_synchronized flag
- __ stbool(G0, do_not_unlock_if_synchronized);
-
- // check for synchronized methods
- // Must happen AFTER invocation_counter check and stack overflow check,
- // so method is not locked if overflows.
-
- if (synchronized) {
- lock_method();
- } else {
-#ifdef ASSERT
- { Label ok;
- __ ld(access_flags, O0);
- __ btst(JVM_ACC_SYNCHRONIZED, O0);
- __ br( Assembler::zero, false, Assembler::pt, ok);
- __ delayed()->nop();
- __ stop("method needs synchronization");
- __ bind(ok);
- }
-#endif // ASSERT
- }
-
- // start execution
-
- __ verify_thread();
-
- // jvmti support
- __ notify_method_entry();
-
- // start executing instructions
- __ dispatch_next(vtos);
-
-
- if (inc_counter) {
- if (ProfileInterpreter) {
- // We have decided to profile this method in the interpreter
- __ bind(profile_method);
-
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
- __ set_method_data_pointer_for_bcp();
- __ ba_short(profile_method_continue);
- }
-
- // handle invocation counter overflow
- __ bind(invocation_counter_overflow);
- generate_counter_overflow(Lcontinue);
- }
-
- return entry;
-}
-
-//----------------------------------------------------------------------------------------------------
-// Exceptions
-void TemplateInterpreterGenerator::generate_throw_exception() {
-
- // Entry point in previous activation (i.e., if the caller was interpreted)
- Interpreter::_rethrow_exception_entry = __ pc();
- // O0: exception
-
- // entry point for exceptions thrown within interpreter code
- Interpreter::_throw_exception_entry = __ pc();
- __ verify_thread();
- // expression stack is undefined here
- // O0: exception, i.e. Oexception
- // Lbcp: exception bcp
- __ verify_oop(Oexception);
-
-
- // expression stack must be empty before entering the VM in case of an exception
- __ empty_expression_stack();
- // find exception handler address and preserve exception oop
- // call C routine to find handler and jump to it
- __ call_VM(O1, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Oexception);
- __ push_ptr(O1); // push exception for exception handler bytecodes
-
- __ JMP(O0, 0); // jump to exception handler (may be remove activation entry!)
- __ delayed()->nop();
-
-
- // if the exception is not handled in the current frame
- // the frame is removed and the exception is rethrown
- // (i.e. exception continuation is _rethrow_exception)
- //
- // Note: At this point the bci is still the bxi for the instruction which caused
- // the exception and the expression stack is empty. Thus, for any VM calls
- // at this point, GC will find a legal oop map (with empty expression stack).
-
- // in current activation
- // tos: exception
- // Lbcp: exception bcp
-
- //
- // JVMTI PopFrame support
- //
-
- Interpreter::_remove_activation_preserving_args_entry = __ pc();
- Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset());
- // Set the popframe_processing bit in popframe_condition indicating that we are
- // currently handling popframe, so that call_VMs that may happen later do not trigger new
- // popframe handling cycles.
-
- __ ld(popframe_condition_addr, G3_scratch);
- __ or3(G3_scratch, JavaThread::popframe_processing_bit, G3_scratch);
- __ stw(G3_scratch, popframe_condition_addr);
-
- // Empty the expression stack, as in normal exception handling
- __ empty_expression_stack();
- __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false);
-
- {
- // Check to see whether we are returning to a deoptimized frame.
- // (The PopFrame call ensures that the caller of the popped frame is
- // either interpreted or compiled and deoptimizes it if compiled.)
- // In this case, we can't call dispatch_next() after the frame is
- // popped, but instead must save the incoming arguments and restore
- // them after deoptimization has occurred.
- //
- // Note that we don't compare the return PC against the
- // deoptimization blob's unpack entry because of the presence of
- // adapter frames in C2.
- Label caller_not_deoptimized;
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), I7);
- __ br_notnull_short(O0, Assembler::pt, caller_not_deoptimized);
-
- const Register Gtmp1 = G3_scratch;
- const Register Gtmp2 = G1_scratch;
- const Register RconstMethod = Gtmp1;
- const Address constMethod(Lmethod, Method::const_offset());
- const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
-
- // Compute size of arguments for saving when returning to deoptimized caller
- __ ld_ptr(constMethod, RconstMethod);
- __ lduh(size_of_parameters, Gtmp1);
- __ sll(Gtmp1, Interpreter::logStackElementSize, Gtmp1);
- __ sub(Llocals, Gtmp1, Gtmp2);
- __ add(Gtmp2, wordSize, Gtmp2);
- // Save these arguments
- __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), G2_thread, Gtmp1, Gtmp2);
- // Inform deoptimization that it is responsible for restoring these arguments
- __ set(JavaThread::popframe_force_deopt_reexecution_bit, Gtmp1);
- Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset());
- __ st(Gtmp1, popframe_condition_addr);
-
- // Return from the current method
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ ret();
- __ delayed()->restore(I5_savedSP, G0, SP);
-
- __ bind(caller_not_deoptimized);
- }
-
- // Clear the popframe condition flag
- __ stw(G0 /* popframe_inactive */, popframe_condition_addr);
-
- // Get out of the current method (how this is done depends on the particular compiler calling
- // convention that the interpreter currently follows)
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ restore(I5_savedSP, G0, SP);
- // The method data pointer was incremented already during
- // call profiling. We have to restore the mdp for the current bcp.
- if (ProfileInterpreter) {
- __ set_method_data_pointer_for_bcp();
- }
-
-#if INCLUDE_JVMTI
- { Label L_done;
-
- __ ldub(Address(Lbcp, 0), G1_scratch); // Load current bytecode
- __ cmp_and_br_short(G1_scratch, Bytecodes::_invokestatic, Assembler::notEqual, Assembler::pn, L_done);
-
- // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
- // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
-
- __ call_VM(G1_scratch, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), I0, Lmethod, Lbcp);
-
- __ br_null(G1_scratch, false, Assembler::pn, L_done);
- __ delayed()->nop();
-
- __ st_ptr(G1_scratch, Lesp, wordSize);
- __ bind(L_done);
- }
-#endif // INCLUDE_JVMTI
-
- // Resume bytecode interpretation at the current bcp
- __ dispatch_next(vtos);
- // end of JVMTI PopFrame support
-
- Interpreter::_remove_activation_entry = __ pc();
-
- // preserve exception over this code sequence (remove activation calls the vm, but oopmaps are not correct here)
- __ pop_ptr(Oexception); // get exception
-
- // Intel has the following comment:
- //// remove the activation (without doing throws on illegalMonitorExceptions)
- // They remove the activation without checking for bad monitor state.
- // %%% We should make sure this is the right semantics before implementing.
-
- __ set_vm_result(Oexception);
- __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false);
-
- __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI);
-
- __ get_vm_result(Oexception);
- __ verify_oop(Oexception);
-
- const int return_reg_adjustment = frame::pc_return_offset;
- Address issuing_pc_addr(I7, return_reg_adjustment);
-
- // We are done with this activation frame; find out where to go next.
- // The continuation point will be an exception handler, which expects
- // the following registers set up:
- //
- // Oexception: exception
- // Oissuing_pc: the local call that threw exception
- // Other On: garbage
- // In/Ln: the contents of the caller's register window
- //
- // We do the required restore at the last possible moment, because we
- // need to preserve some state across a runtime call.
- // (Remember that the caller activation is unknown--it might not be
- // interpreted, so things like Lscratch are useless in the caller.)
-
- // Although the Intel version uses call_C, we can use the more
- // compact call_VM. (The only real difference on SPARC is a
- // harmlessly ignored [re]set_last_Java_frame, compared with
- // the Intel code which lacks this.)
- __ mov(Oexception, Oexception ->after_save()); // get exception in I0 so it will be on O0 after restore
- __ add(issuing_pc_addr, Oissuing_pc->after_save()); // likewise set I1 to a value local to the caller
- __ super_call_VM_leaf(L7_thread_cache,
- CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
- G2_thread, Oissuing_pc->after_save());
-
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ JMP(O0, 0); // return exception handler in caller
- __ delayed()->restore(I5_savedSP, G0, SP);
-
- // (same old exception object is already in Oexception; see above)
- // Note that an "issuing PC" is actually the next PC after the call
-}
-
-
-//
-// JVMTI ForceEarlyReturn support
-//
-
-address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
- address entry = __ pc();
-
- __ empty_expression_stack();
- __ load_earlyret_value(state);
-
- __ ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), G3_scratch);
- Address cond_addr(G3_scratch, JvmtiThreadState::earlyret_state_offset());
-
- // Clear the earlyret state
- __ stw(G0 /* JvmtiThreadState::earlyret_inactive */, cond_addr);
-
- __ remove_activation(state,
- /* throw_monitor_exception */ false,
- /* install_monitor_exception */ false);
-
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ ret(); // return to caller
- __ delayed()->restore(I5_savedSP, G0, SP);
-
- return entry;
-} // end of JVMTI ForceEarlyReturn support
-
-
-//------------------------------------------------------------------------------------------------------------------------
-// Helper for vtos entry point generation
-
-void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
- assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
- Label L;
- aep = __ pc(); __ push_ptr(); __ ba_short(L);
- fep = __ pc(); __ push_f(); __ ba_short(L);
- dep = __ pc(); __ push_d(); __ ba_short(L);
- lep = __ pc(); __ push_l(); __ ba_short(L);
- iep = __ pc(); __ push_i();
- bep = cep = sep = iep; // there aren't any
- vep = __ pc(); __ bind(L); // fall through
- generate_and_dispatch(t);
-}
-
-// --------------------------------------------------------------------------------
-
-// Non-product code
-#ifndef PRODUCT
-address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
- address entry = __ pc();
-
- __ push(state);
- __ mov(O7, Lscratch); // protect return address within interpreter
-
- // Pass a 0 (not used in sparc) and the top of stack to the bytecode tracer
- __ mov( Otos_l2, G3_scratch );
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), G0, Otos_l1, G3_scratch);
- __ mov(Lscratch, O7); // restore return address
- __ pop(state);
- __ retl();
- __ delayed()->nop();
-
- return entry;
-}
-
-
-// helpers for generate_and_dispatch
-
-void TemplateInterpreterGenerator::count_bytecode() {
- __ inc_counter(&BytecodeCounter::_counter_value, G3_scratch, G4_scratch);
-}
-
-
-void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
- __ inc_counter(&BytecodeHistogram::_counters[t->bytecode()], G3_scratch, G4_scratch);
-}
-
-
-void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
- AddressLiteral index (&BytecodePairHistogram::_index);
- AddressLiteral counters((address) &BytecodePairHistogram::_counters);
-
- // get index, shift out old bytecode, bring in new bytecode, and store it
- // _index = (_index >> log2_number_of_codes) |
- // (bytecode << log2_number_of_codes);
-
- __ load_contents(index, G4_scratch);
- __ srl( G4_scratch, BytecodePairHistogram::log2_number_of_codes, G4_scratch );
- __ set( ((int)t->bytecode()) << BytecodePairHistogram::log2_number_of_codes, G3_scratch );
- __ or3( G3_scratch, G4_scratch, G4_scratch );
- __ store_contents(G4_scratch, index, G3_scratch);
-
- // bump bucket contents
- // _counters[_index] ++;
-
- __ set(counters, G3_scratch); // loads into G3_scratch
- __ sll( G4_scratch, LogBytesPerWord, G4_scratch ); // Index is word address
- __ add (G3_scratch, G4_scratch, G3_scratch); // Add in index
- __ ld (G3_scratch, 0, G4_scratch);
- __ inc (G4_scratch);
- __ st (G4_scratch, 0, G3_scratch);
-}
-
-
-void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
- // Call a little run-time stub to avoid blow-up for each bytecode.
- // The run-time runtime saves the right registers, depending on
- // the tosca in-state for the given template.
- address entry = Interpreter::trace_code(t->tos_in());
- guarantee(entry != NULL, "entry must have been generated");
- __ call(entry, relocInfo::none);
- __ delayed()->nop();
-}
-
-
-void TemplateInterpreterGenerator::stop_interpreter_at() {
- AddressLiteral counter(&BytecodeCounter::_counter_value);
- __ load_contents(counter, G3_scratch);
- AddressLiteral stop_at(&StopInterpreterAt);
- __ load_ptr_contents(stop_at, G4_scratch);
- __ cmp(G3_scratch, G4_scratch);
- __ breakpoint_trap(Assembler::equal, Assembler::icc);
-}
-#endif // not PRODUCT
diff --git a/src/hotspot/cpu/sparc/templateTable_sparc.cpp b/src/hotspot/cpu/sparc/templateTable_sparc.cpp
deleted file mode 100644
index 6b5d878da16..00000000000
--- a/src/hotspot/cpu/sparc/templateTable_sparc.cpp
+++ /dev/null
@@ -1,3862 +0,0 @@
-/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "asm/macroAssembler.inline.hpp"
-#include "gc/shared/barrierSetAssembler.hpp"
-#include "interpreter/interpreter.hpp"
-#include "interpreter/interpreterRuntime.hpp"
-#include "interpreter/interp_masm.hpp"
-#include "interpreter/templateTable.hpp"
-#include "memory/universe.hpp"
-#include "oops/methodData.hpp"
-#include "oops/objArrayKlass.hpp"
-#include "oops/oop.inline.hpp"
-#include "prims/methodHandles.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/safepointMechanism.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/synchronizer.hpp"
-#include "utilities/macros.hpp"
-
-#define __ _masm->
-
-// Misc helpers
-
-// Do an oop store like *(base + index + offset) = val
-// index can be noreg,
-static void do_oop_store(InterpreterMacroAssembler* _masm,
- Register base,
- Register index,
- int offset,
- Register val,
- Register tmp,
- DecoratorSet decorators = 0) {
- assert(tmp != val && tmp != base && tmp != index, "register collision");
- assert(index == noreg || offset == 0, "only one offset");
- if (index == noreg) {
- __ store_heap_oop(val, base, offset, tmp, decorators);
- } else {
- __ store_heap_oop(val, base, index, tmp, decorators);
- }
-}
-
-// Do an oop load like val = *(base + index + offset)
-// index can be noreg.
-static void do_oop_load(InterpreterMacroAssembler* _masm,
- Register base,
- Register index,
- int offset,
- Register dst,
- Register tmp,
- DecoratorSet decorators = 0) {
- assert(tmp != dst && tmp != base && tmp != index, "register collision");
- assert(index == noreg || offset == 0, "only one offset");
- if (index == noreg) {
- __ load_heap_oop(base, offset, dst, tmp, decorators);
- } else {
- __ load_heap_oop(base, index, dst, tmp, decorators);
- }
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Platform-dependent initialization
-
-void TemplateTable::pd_initialize() {
- // (none)
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Condition conversion
-Assembler::Condition ccNot(TemplateTable::Condition cc) {
- switch (cc) {
- case TemplateTable::equal : return Assembler::notEqual;
- case TemplateTable::not_equal : return Assembler::equal;
- case TemplateTable::less : return Assembler::greaterEqual;
- case TemplateTable::less_equal : return Assembler::greater;
- case TemplateTable::greater : return Assembler::lessEqual;
- case TemplateTable::greater_equal: return Assembler::less;
- }
- ShouldNotReachHere();
- return Assembler::zero;
-}
-
-//----------------------------------------------------------------------------------------------------
-// Miscelaneous helper routines
-
-
-Address TemplateTable::at_bcp(int offset) {
- assert(_desc->uses_bcp(), "inconsistent uses_bcp information");
- return Address(Lbcp, offset);
-}
-
-
-void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
- Register temp_reg, bool load_bc_into_bc_reg/*=true*/,
- int byte_no) {
- // With sharing on, may need to test Method* flag.
- if (!RewriteBytecodes) return;
- Label L_patch_done;
-
- switch (bc) {
- case Bytecodes::_fast_aputfield:
- case Bytecodes::_fast_bputfield:
- case Bytecodes::_fast_zputfield:
- case Bytecodes::_fast_cputfield:
- case Bytecodes::_fast_dputfield:
- case Bytecodes::_fast_fputfield:
- case Bytecodes::_fast_iputfield:
- case Bytecodes::_fast_lputfield:
- case Bytecodes::_fast_sputfield:
- {
- // We skip bytecode quickening for putfield instructions when
- // the put_code written to the constant pool cache is zero.
- // This is required so that every execution of this instruction
- // calls out to InterpreterRuntime::resolve_get_put to do
- // additional, required work.
- assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
- assert(load_bc_into_bc_reg, "we use bc_reg as temp");
- __ get_cache_and_index_and_bytecode_at_bcp(bc_reg, temp_reg, temp_reg, byte_no, 1);
- __ set(bc, bc_reg);
- __ cmp_and_br_short(temp_reg, 0, Assembler::equal, Assembler::pn, L_patch_done); // don't patch
- }
- break;
- default:
- assert(byte_no == -1, "sanity");
- if (load_bc_into_bc_reg) {
- __ set(bc, bc_reg);
- }
- }
-
- if (JvmtiExport::can_post_breakpoint()) {
- Label L_fast_patch;
- __ ldub(at_bcp(0), temp_reg);
- __ cmp_and_br_short(temp_reg, Bytecodes::_breakpoint, Assembler::notEqual, Assembler::pt, L_fast_patch);
- // perform the quickening, slowly, in the bowels of the breakpoint table
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), Lmethod, Lbcp, bc_reg);
- __ ba_short(L_patch_done);
- __ bind(L_fast_patch);
- }
-
-#ifdef ASSERT
- Bytecodes::Code orig_bytecode = Bytecodes::java_code(bc);
- Label L_okay;
- __ ldub(at_bcp(0), temp_reg);
- __ cmp(temp_reg, orig_bytecode);
- __ br(Assembler::equal, false, Assembler::pt, L_okay);
- __ delayed()->cmp(temp_reg, bc_reg);
- __ br(Assembler::equal, false, Assembler::pt, L_okay);
- __ delayed()->nop();
- __ stop("patching the wrong bytecode");
- __ bind(L_okay);
-#endif
-
- // patch bytecode
- __ stb(bc_reg, at_bcp(0));
- __ bind(L_patch_done);
-}
-
-//----------------------------------------------------------------------------------------------------
-// Individual instructions
-
-void TemplateTable::nop() {
- transition(vtos, vtos);
- // nothing to do
-}
-
-void TemplateTable::shouldnotreachhere() {
- transition(vtos, vtos);
- __ stop("shouldnotreachhere bytecode");
-}
-
-void TemplateTable::aconst_null() {
- transition(vtos, atos);
- __ clr(Otos_i);
-}
-
-
-void TemplateTable::iconst(int value) {
- transition(vtos, itos);
- __ set(value, Otos_i);
-}
-
-
-void TemplateTable::lconst(int value) {
- transition(vtos, ltos);
- assert(value >= 0, "check this code");
- __ set(value, Otos_l);
-}
-
-
-void TemplateTable::fconst(int value) {
- transition(vtos, ftos);
- static float zero = 0.0, one = 1.0, two = 2.0;
- float* p;
- switch( value ) {
- default: ShouldNotReachHere();
- case 0: p = &zero; break;
- case 1: p = &one; break;
- case 2: p = &two; break;
- }
- AddressLiteral a(p);
- __ sethi(a, G3_scratch);
- __ ldf(FloatRegisterImpl::S, G3_scratch, a.low10(), Ftos_f);
-}
-
-
-void TemplateTable::dconst(int value) {
- transition(vtos, dtos);
- static double zero = 0.0, one = 1.0;
- double* p;
- switch( value ) {
- default: ShouldNotReachHere();
- case 0: p = &zero; break;
- case 1: p = &one; break;
- }
- AddressLiteral a(p);
- __ sethi(a, G3_scratch);
- __ ldf(FloatRegisterImpl::D, G3_scratch, a.low10(), Ftos_d);
-}
-
-
-// %%%%% Should factore most snippet templates across platforms
-
-void TemplateTable::bipush() {
- transition(vtos, itos);
- __ ldsb( at_bcp(1), Otos_i );
-}
-
-void TemplateTable::sipush() {
- transition(vtos, itos);
- __ get_2_byte_integer_at_bcp(1, G3_scratch, Otos_i, InterpreterMacroAssembler::Signed);
-}
-
-void TemplateTable::ldc(bool wide) {
- transition(vtos, vtos);
- Label call_ldc, notInt, isString, notString, notClass, notFloat, exit;
-
- if (wide) {
- __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned);
- } else {
- __ ldub(Lbcp, 1, O1);
- }
- __ get_cpool_and_tags(O0, O2);
-
- const int base_offset = ConstantPool::header_size() * wordSize;
- const int tags_offset = Array::base_offset_in_bytes();
-
- // get type from tags
- __ add(O2, tags_offset, O2);
- __ ldub(O2, O1, O2);
-
- // unresolved class? If so, must resolve
- __ cmp_and_brx_short(O2, JVM_CONSTANT_UnresolvedClass, Assembler::equal, Assembler::pt, call_ldc);
-
- // unresolved class in error state
- __ cmp_and_brx_short(O2, JVM_CONSTANT_UnresolvedClassInError, Assembler::equal, Assembler::pn, call_ldc);
-
- __ cmp(O2, JVM_CONSTANT_Class); // need to call vm to get java mirror of the class
- __ brx(Assembler::notEqual, true, Assembler::pt, notClass);
- __ delayed()->add(O0, base_offset, O0);
-
- __ bind(call_ldc);
- __ set(wide, O1);
- call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), O1);
- __ push(atos);
- __ ba(exit);
- __ delayed()->nop();
-
- __ bind(notClass);
- // __ add(O0, base_offset, O0);
- __ sll(O1, LogBytesPerWord, O1);
- __ cmp(O2, JVM_CONSTANT_Integer);
- __ brx(Assembler::notEqual, true, Assembler::pt, notInt);
- __ delayed()->cmp(O2, JVM_CONSTANT_String);
- __ ld(O0, O1, Otos_i);
- __ push(itos);
- __ ba(exit);
- __ delayed()->nop();
-
- __ bind(notInt);
- // __ cmp(O2, JVM_CONSTANT_String);
- __ brx(Assembler::notEqual, true, Assembler::pt, notString);
- __ delayed()->cmp(O2, JVM_CONSTANT_Float);
- __ bind(isString);
- __ stop("string should be rewritten to fast_aldc");
- __ ba(exit);
- __ delayed()->nop();
-
- __ bind(notString);
- //__ cmp(O2, JVM_CONSTANT_Float);
- __ brx(Assembler::notEqual, true, Assembler::pt, notFloat);
- __ delayed()->nop();
- __ ldf(FloatRegisterImpl::S, O0, O1, Ftos_f);
- __ push(ftos);
- __ ba(exit);
- __ delayed()->nop();
-
- // assume the tag is for condy; if not, the VM runtime will tell us
- __ bind(notFloat);
- condy_helper(exit);
-
- __ bind(exit);
-}
-
-// Fast path for caching oop constants.
-// %%% We should use this to handle Class and String constants also.
-// %%% It will simplify the ldc/primitive path considerably.
-void TemplateTable::fast_aldc(bool wide) {
- transition(vtos, atos);
-
- int index_size = wide ? sizeof(u2) : sizeof(u1);
- Label resolved;
-
- // We are resolved if the resolved reference cache entry contains a
- // non-null object (CallSite, etc.)
- assert_different_registers(Otos_i, G3_scratch);
- __ get_cache_index_at_bcp(Otos_i, G3_scratch, 1, index_size); // load index => G3_scratch
- __ load_resolved_reference_at_index(Otos_i, G3_scratch, Lscratch);
- __ tst(Otos_i);
- __ br(Assembler::notEqual, false, Assembler::pt, resolved);
- __ delayed()->set((int)bytecode(), O1);
-
- address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);
-
- // first time invocation - must resolve first
- __ call_VM(Otos_i, entry, O1);
- __ bind(resolved);
-
- { // Check for the null sentinel.
- // If we just called the VM, it already did the mapping for us,
- // but it's harmless to retry.
- Label notNull;
- __ set(ExternalAddress((address)Universe::the_null_sentinel_addr()), G3_scratch);
- __ ld_ptr(G3_scratch, 0, G3_scratch);
- __ cmp(G3_scratch, Otos_i);
- __ br(Assembler::notEqual, true, Assembler::pt, notNull);
- __ delayed()->nop();
- __ clr(Otos_i); // NULL object reference
- __ bind(notNull);
- }
-
- // Safe to call with 0 result
- __ verify_oop(Otos_i);
-}
-
-void TemplateTable::ldc2_w() {
- transition(vtos, vtos);
- Label notDouble, notLong, exit;
-
- __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned);
- __ get_cpool_and_tags(O0, O2);
-
- const int base_offset = ConstantPool::header_size() * wordSize;
- const int tags_offset = Array::base_offset_in_bytes();
- // get type from tags
- __ add(O2, tags_offset, O2);
- __ ldub(O2, O1, O2);
-
- __ sll(O1, LogBytesPerWord, O1);
- __ add(O0, O1, G3_scratch);
-
- __ cmp_and_brx_short(O2, JVM_CONSTANT_Double, Assembler::notEqual, Assembler::pt, notDouble);
- // A double can be placed at word-aligned locations in the constant pool.
- // Check out Conversions.java for an example.
- // Also ConstantPool::header_size() is 20, which makes it very difficult
- // to double-align double on the constant pool. SG, 11/7/97
- __ ldf(FloatRegisterImpl::D, G3_scratch, base_offset, Ftos_d);
- __ push(dtos);
- __ ba_short(exit);
-
- __ bind(notDouble);
- __ cmp_and_brx_short(O2, JVM_CONSTANT_Long, Assembler::notEqual, Assembler::pt, notLong);
- __ ldx(G3_scratch, base_offset, Otos_l);
- __ push(ltos);
- __ ba_short(exit);
-
- __ bind(notLong);
- condy_helper(exit);
-
- __ bind(exit);
-}
-
-void TemplateTable::condy_helper(Label& exit) {
- Register Robj = Otos_i;
- Register Roffset = G4_scratch;
- Register Rflags = G1_scratch;
-
- address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);
-
- __ set((int)bytecode(), O1);
- __ call_VM(Robj, entry, O1);
-
- // Get vm_result_2 has flags = (tos, off) using format CPCE::_flags
- __ get_vm_result_2(G3_scratch);
-
- // Get offset
- __ set((int)ConstantPoolCacheEntry::field_index_mask, Roffset);
- __ and3(G3_scratch, Roffset, Roffset);
-
- // compute type
- __ srl(G3_scratch, ConstantPoolCacheEntry::tos_state_shift, Rflags);
- // Make sure we don't need to mask Rflags after the above shift
- ConstantPoolCacheEntry::verify_tos_state_shift();
-
- switch (bytecode()) {
- case Bytecodes::_ldc:
- case Bytecodes::_ldc_w:
- {
- // tos in (itos, ftos, stos, btos, ctos, ztos)
- Label notInt, notFloat, notShort, notByte, notChar, notBool;
- __ cmp(Rflags, itos);
- __ br(Assembler::notEqual, false, Assembler::pt, notInt);
- __ delayed()->cmp(Rflags, ftos);
- // itos
- __ ld(Robj, Roffset, Otos_i);
- __ push(itos);
- __ ba_short(exit);
-
- __ bind(notInt);
- __ br(Assembler::notEqual, false, Assembler::pt, notFloat);
- __ delayed()->cmp(Rflags, stos);
- // ftos
- __ ldf(FloatRegisterImpl::S, Robj, Roffset, Ftos_f);
- __ push(ftos);
- __ ba_short(exit);
-
- __ bind(notFloat);
- __ br(Assembler::notEqual, false, Assembler::pt, notShort);
- __ delayed()->cmp(Rflags, btos);
- // stos
- __ ldsh(Robj, Roffset, Otos_i);
- __ push(itos);
- __ ba_short(exit);
-
- __ bind(notShort);
- __ br(Assembler::notEqual, false, Assembler::pt, notByte);
- __ delayed()->cmp(Rflags, ctos);
- // btos
- __ ldsb(Robj, Roffset, Otos_i);
- __ push(itos);
- __ ba_short(exit);
-
- __ bind(notByte);
- __ br(Assembler::notEqual, false, Assembler::pt, notChar);
- __ delayed()->cmp(Rflags, ztos);
- // ctos
- __ lduh(Robj, Roffset, Otos_i);
- __ push(itos);
- __ ba_short(exit);
-
- __ bind(notChar);
- __ br(Assembler::notEqual, false, Assembler::pt, notBool);
- __ delayed()->nop();
- // ztos
- __ ldsb(Robj, Roffset, Otos_i);
- __ push(itos);
- __ ba_short(exit);
-
- __ bind(notBool);
- break;
- }
-
- case Bytecodes::_ldc2_w:
- {
- Label notLong, notDouble;
- __ cmp(Rflags, ltos);
- __ br(Assembler::notEqual, false, Assembler::pt, notLong);
- __ delayed()->cmp(Rflags, dtos);
- // ltos
- // load must be atomic
- __ ld_long(Robj, Roffset, Otos_l);
- __ push(ltos);
- __ ba_short(exit);
-
- __ bind(notLong);
- __ br(Assembler::notEqual, false, Assembler::pt, notDouble);
- __ delayed()->nop();
- // dtos
- __ ldf(FloatRegisterImpl::D, Robj, Roffset, Ftos_d);
- __ push(dtos);
- __ ba_short(exit);
-
- __ bind(notDouble);
- break;
- }
-
- default:
- ShouldNotReachHere();
- }
-
- __ stop("bad ldc/condy");
-
- __ bind(exit);
-}
-
-void TemplateTable::locals_index(Register reg, int offset) {
- __ ldub( at_bcp(offset), reg );
-}
-
-void TemplateTable::locals_index_wide(Register reg) {
- // offset is 2, not 1, because Lbcp points to wide prefix code
- __ get_2_byte_integer_at_bcp(2, G4_scratch, reg, InterpreterMacroAssembler::Unsigned);
-}
-
-void TemplateTable::iload() {
- iload_internal();
-}
-
-void TemplateTable::nofast_iload() {
- iload_internal(may_not_rewrite);
-}
-
-void TemplateTable::iload_internal(RewriteControl rc) {
- transition(vtos, itos);
- // Rewrite iload,iload pair into fast_iload2
- // iload,caload pair into fast_icaload
- if (RewriteFrequentPairs && rc == may_rewrite) {
- Label rewrite, done;
-
- // get next byte
- __ ldub(at_bcp(Bytecodes::length_for(Bytecodes::_iload)), G3_scratch);
-
- // if _iload, wait to rewrite to iload2. We only want to rewrite the
- // last two iloads in a pair. Comparing against fast_iload means that
- // the next bytecode is neither an iload or a caload, and therefore
- // an iload pair.
- __ cmp_and_br_short(G3_scratch, (int)Bytecodes::_iload, Assembler::equal, Assembler::pn, done);
-
- __ cmp(G3_scratch, (int)Bytecodes::_fast_iload);
- __ br(Assembler::equal, false, Assembler::pn, rewrite);
- __ delayed()->set(Bytecodes::_fast_iload2, G4_scratch);
-
- __ cmp(G3_scratch, (int)Bytecodes::_caload);
- __ br(Assembler::equal, false, Assembler::pn, rewrite);
- __ delayed()->set(Bytecodes::_fast_icaload, G4_scratch);
-
- __ set(Bytecodes::_fast_iload, G4_scratch); // don't check again
- // rewrite
- // G4_scratch: fast bytecode
- __ bind(rewrite);
- patch_bytecode(Bytecodes::_iload, G4_scratch, G3_scratch, false);
- __ bind(done);
- }
-
- // Get the local value into tos
- locals_index(G3_scratch);
- __ access_local_int( G3_scratch, Otos_i );
-}
-
-void TemplateTable::fast_iload2() {
- transition(vtos, itos);
- locals_index(G3_scratch);
- __ access_local_int( G3_scratch, Otos_i );
- __ push_i();
- locals_index(G3_scratch, 3); // get next bytecode's local index.
- __ access_local_int( G3_scratch, Otos_i );
-}
-
-void TemplateTable::fast_iload() {
- transition(vtos, itos);
- locals_index(G3_scratch);
- __ access_local_int( G3_scratch, Otos_i );
-}
-
-void TemplateTable::lload() {
- transition(vtos, ltos);
- locals_index(G3_scratch);
- __ access_local_long( G3_scratch, Otos_l );
-}
-
-
-void TemplateTable::fload() {
- transition(vtos, ftos);
- locals_index(G3_scratch);
- __ access_local_float( G3_scratch, Ftos_f );
-}
-
-
-void TemplateTable::dload() {
- transition(vtos, dtos);
- locals_index(G3_scratch);
- __ access_local_double( G3_scratch, Ftos_d );
-}
-
-
-void TemplateTable::aload() {
- transition(vtos, atos);
- locals_index(G3_scratch);
- __ access_local_ptr( G3_scratch, Otos_i);
-}
-
-
-void TemplateTable::wide_iload() {
- transition(vtos, itos);
- locals_index_wide(G3_scratch);
- __ access_local_int( G3_scratch, Otos_i );
-}
-
-
-void TemplateTable::wide_lload() {
- transition(vtos, ltos);
- locals_index_wide(G3_scratch);
- __ access_local_long( G3_scratch, Otos_l );
-}
-
-
-void TemplateTable::wide_fload() {
- transition(vtos, ftos);
- locals_index_wide(G3_scratch);
- __ access_local_float( G3_scratch, Ftos_f );
-}
-
-
-void TemplateTable::wide_dload() {
- transition(vtos, dtos);
- locals_index_wide(G3_scratch);
- __ access_local_double( G3_scratch, Ftos_d );
-}
-
-
-void TemplateTable::wide_aload() {
- transition(vtos, atos);
- locals_index_wide(G3_scratch);
- __ access_local_ptr( G3_scratch, Otos_i );
- __ verify_oop(Otos_i);
-}
-
-
-void TemplateTable::iaload() {
- transition(itos, itos);
- // Otos_i: index
- // tos: array
- __ index_check(O2, Otos_i, LogBytesPerInt, G3_scratch, O3);
- __ ld(O3, arrayOopDesc::base_offset_in_bytes(T_INT), Otos_i);
-}
-
-
-void TemplateTable::laload() {
- transition(itos, ltos);
- // Otos_i: index
- // O2: array
- __ index_check(O2, Otos_i, LogBytesPerLong, G3_scratch, O3);
- __ ld_long(O3, arrayOopDesc::base_offset_in_bytes(T_LONG), Otos_l);
-}
-
-
-void TemplateTable::faload() {
- transition(itos, ftos);
- // Otos_i: index
- // O2: array
- __ index_check(O2, Otos_i, LogBytesPerInt, G3_scratch, O3);
- __ ldf(FloatRegisterImpl::S, O3, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Ftos_f);
-}
-
-
-void TemplateTable::daload() {
- transition(itos, dtos);
- // Otos_i: index
- // O2: array
- __ index_check(O2, Otos_i, LogBytesPerLong, G3_scratch, O3);
- __ ldf(FloatRegisterImpl::D, O3, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Ftos_d);
-}
-
-
-void TemplateTable::aaload() {
- transition(itos, atos);
- // Otos_i: index
- // tos: array
- __ index_check(O2, Otos_i, UseCompressedOops ? 2 : LogBytesPerWord, G3_scratch, O3);
- do_oop_load(_masm,
- O3,
- noreg,
- arrayOopDesc::base_offset_in_bytes(T_OBJECT),
- Otos_i,
- G3_scratch,
- IS_ARRAY);
- __ verify_oop(Otos_i);
-}
-
-
-void TemplateTable::baload() {
- transition(itos, itos);
- // Otos_i: index
- // tos: array
- __ index_check(O2, Otos_i, 0, G3_scratch, O3);
- __ ldsb(O3, arrayOopDesc::base_offset_in_bytes(T_BYTE), Otos_i);
-}
-
-
-void TemplateTable::caload() {
- transition(itos, itos);
- // Otos_i: index
- // tos: array
- __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3);
- __ lduh(O3, arrayOopDesc::base_offset_in_bytes(T_CHAR), Otos_i);
-}
-
-void TemplateTable::fast_icaload() {
- transition(vtos, itos);
- // Otos_i: index
- // tos: array
- locals_index(G3_scratch);
- __ access_local_int( G3_scratch, Otos_i );
- __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3);
- __ lduh(O3, arrayOopDesc::base_offset_in_bytes(T_CHAR), Otos_i);
-}
-
-
-void TemplateTable::saload() {
- transition(itos, itos);
- // Otos_i: index
- // tos: array
- __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3);
- __ ldsh(O3, arrayOopDesc::base_offset_in_bytes(T_SHORT), Otos_i);
-}
-
-
-void TemplateTable::iload(int n) {
- transition(vtos, itos);
- __ ld( Llocals, Interpreter::local_offset_in_bytes(n), Otos_i );
-}
-
-
-void TemplateTable::lload(int n) {
- transition(vtos, ltos);
- assert(n+1 < Argument::n_register_parameters, "would need more code");
- __ load_unaligned_long(Llocals, Interpreter::local_offset_in_bytes(n+1), Otos_l);
-}
-
-
-void TemplateTable::fload(int n) {
- transition(vtos, ftos);
- assert(n < Argument::n_register_parameters, "would need more code");
- __ ldf( FloatRegisterImpl::S, Llocals, Interpreter::local_offset_in_bytes(n), Ftos_f );
-}
-
-
-void TemplateTable::dload(int n) {
- transition(vtos, dtos);
- FloatRegister dst = Ftos_d;
- __ load_unaligned_double(Llocals, Interpreter::local_offset_in_bytes(n+1), dst);
-}
-
-
-void TemplateTable::aload(int n) {
- transition(vtos, atos);
- __ ld_ptr( Llocals, Interpreter::local_offset_in_bytes(n), Otos_i );
-}
-
-void TemplateTable::aload_0() {
- aload_0_internal();
-}
-
-void TemplateTable::nofast_aload_0() {
- aload_0_internal(may_not_rewrite);
-}
-
-void TemplateTable::aload_0_internal(RewriteControl rc) {
- transition(vtos, atos);
-
- // According to bytecode histograms, the pairs:
- //
- // _aload_0, _fast_igetfield (itos)
- // _aload_0, _fast_agetfield (atos)
- // _aload_0, _fast_fgetfield (ftos)
- //
- // occur frequently. If RewriteFrequentPairs is set, the (slow) _aload_0
- // bytecode checks the next bytecode and then rewrites the current
- // bytecode into a pair bytecode; otherwise it rewrites the current
- // bytecode into _fast_aload_0 that doesn't do the pair check anymore.
- //
- if (RewriteFrequentPairs && rc == may_rewrite) {
- Label rewrite, done;
-
- // get next byte
- __ ldub(at_bcp(Bytecodes::length_for(Bytecodes::_aload_0)), G3_scratch);
-
- // if _getfield then wait with rewrite
- __ cmp_and_br_short(G3_scratch, (int)Bytecodes::_getfield, Assembler::equal, Assembler::pn, done);
-
- // if _igetfield then rewrite to _fast_iaccess_0
- assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def");
- __ cmp(G3_scratch, (int)Bytecodes::_fast_igetfield);
- __ br(Assembler::equal, false, Assembler::pn, rewrite);
- __ delayed()->set(Bytecodes::_fast_iaccess_0, G4_scratch);
-
- // if _agetfield then rewrite to _fast_aaccess_0
- assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def");
- __ cmp(G3_scratch, (int)Bytecodes::_fast_agetfield);
- __ br(Assembler::equal, false, Assembler::pn, rewrite);
- __ delayed()->set(Bytecodes::_fast_aaccess_0, G4_scratch);
-
- // if _fgetfield then rewrite to _fast_faccess_0
- assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def");
- __ cmp(G3_scratch, (int)Bytecodes::_fast_fgetfield);
- __ br(Assembler::equal, false, Assembler::pn, rewrite);
- __ delayed()->set(Bytecodes::_fast_faccess_0, G4_scratch);
-
- // else rewrite to _fast_aload0
- assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "adjust fast bytecode def");
- __ set(Bytecodes::_fast_aload_0, G4_scratch);
-
- // rewrite
- // G4_scratch: fast bytecode
- __ bind(rewrite);
- patch_bytecode(Bytecodes::_aload_0, G4_scratch, G3_scratch, false);
- __ bind(done);
- }
-
- // Do actual aload_0 (must do this after patch_bytecode which might call VM and GC might change oop).
- aload(0);
-}
-
-void TemplateTable::istore() {
- transition(itos, vtos);
- locals_index(G3_scratch);
- __ store_local_int( G3_scratch, Otos_i );
-}
-
-
-void TemplateTable::lstore() {
- transition(ltos, vtos);
- locals_index(G3_scratch);
- __ store_local_long( G3_scratch, Otos_l );
-}
-
-
-void TemplateTable::fstore() {
- transition(ftos, vtos);
- locals_index(G3_scratch);
- __ store_local_float( G3_scratch, Ftos_f );
-}
-
-
-void TemplateTable::dstore() {
- transition(dtos, vtos);
- locals_index(G3_scratch);
- __ store_local_double( G3_scratch, Ftos_d );
-}
-
-
-void TemplateTable::astore() {
- transition(vtos, vtos);
- __ load_ptr(0, Otos_i);
- __ inc(Lesp, Interpreter::stackElementSize);
- __ verify_oop_or_return_address(Otos_i, G3_scratch);
- locals_index(G3_scratch);
- __ store_local_ptr(G3_scratch, Otos_i);
-}
-
-
-void TemplateTable::wide_istore() {
- transition(vtos, vtos);
- __ pop_i();
- locals_index_wide(G3_scratch);
- __ store_local_int( G3_scratch, Otos_i );
-}
-
-
-void TemplateTable::wide_lstore() {
- transition(vtos, vtos);
- __ pop_l();
- locals_index_wide(G3_scratch);
- __ store_local_long( G3_scratch, Otos_l );
-}
-
-
-void TemplateTable::wide_fstore() {
- transition(vtos, vtos);
- __ pop_f();
- locals_index_wide(G3_scratch);
- __ store_local_float( G3_scratch, Ftos_f );
-}
-
-
-void TemplateTable::wide_dstore() {
- transition(vtos, vtos);
- __ pop_d();
- locals_index_wide(G3_scratch);
- __ store_local_double( G3_scratch, Ftos_d );
-}
-
-
-void TemplateTable::wide_astore() {
- transition(vtos, vtos);
- __ load_ptr(0, Otos_i);
- __ inc(Lesp, Interpreter::stackElementSize);
- __ verify_oop_or_return_address(Otos_i, G3_scratch);
- locals_index_wide(G3_scratch);
- __ store_local_ptr(G3_scratch, Otos_i);
-}
-
-
-void TemplateTable::iastore() {
- transition(itos, vtos);
- __ pop_i(O2); // index
- // Otos_i: val
- // O3: array
- __ index_check(O3, O2, LogBytesPerInt, G3_scratch, O2);
- __ st(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_INT));
-}
-
-
-void TemplateTable::lastore() {
- transition(ltos, vtos);
- __ pop_i(O2); // index
- // Otos_l: val
- // O3: array
- __ index_check(O3, O2, LogBytesPerLong, G3_scratch, O2);
- __ st_long(Otos_l, O2, arrayOopDesc::base_offset_in_bytes(T_LONG));
-}
-
-
-void TemplateTable::fastore() {
- transition(ftos, vtos);
- __ pop_i(O2); // index
- // Ftos_f: val
- // O3: array
- __ index_check(O3, O2, LogBytesPerInt, G3_scratch, O2);
- __ stf(FloatRegisterImpl::S, Ftos_f, O2, arrayOopDesc::base_offset_in_bytes(T_FLOAT));
-}
-
-
-void TemplateTable::dastore() {
- transition(dtos, vtos);
- __ pop_i(O2); // index
- // Fos_d: val
- // O3: array
- __ index_check(O3, O2, LogBytesPerLong, G3_scratch, O2);
- __ stf(FloatRegisterImpl::D, Ftos_d, O2, arrayOopDesc::base_offset_in_bytes(T_DOUBLE));
-}
-
-
-void TemplateTable::aastore() {
- Label store_ok, is_null, done;
- transition(vtos, vtos);
- __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), Otos_i);
- __ ld(Lesp, Interpreter::expr_offset_in_bytes(1), O2); // get index
- __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(2), O3); // get array
- // Otos_i: val
- // O2: index
- // O3: array
- __ verify_oop(Otos_i);
- __ index_check_without_pop(O3, O2, UseCompressedOops ? 2 : LogBytesPerWord, G3_scratch, O1);
-
- // do array store check - check for NULL value first
- __ br_null_short( Otos_i, Assembler::pn, is_null );
-
- __ load_klass(O3, O4); // get array klass
- __ load_klass(Otos_i, O5); // get value klass
-
- // do fast instanceof cache test
-
- __ ld_ptr(O4, in_bytes(ObjArrayKlass::element_klass_offset()), O4);
-
- assert(Otos_i == O0, "just checking");
-
- // Otos_i: value
- // O1: addr - offset
- // O2: index
- // O3: array
- // O4: array element klass
- // O5: value klass
-
- // Address element(O1, 0, arrayOopDesc::base_offset_in_bytes(T_OBJECT));
-
- // Generate a fast subtype check. Branch to store_ok if no
- // failure. Throw if failure.
- __ gen_subtype_check( O5, O4, G3_scratch, G4_scratch, G1_scratch, store_ok );
-
- // Not a subtype; so must throw exception
- __ throw_if_not_x( Assembler::never, Interpreter::_throw_ArrayStoreException_entry, G3_scratch );
-
- // Store is OK.
- __ bind(store_ok);
- do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i, G3_scratch, IS_ARRAY);
-
- __ ba(done);
- __ delayed()->inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value)
-
- __ bind(is_null);
- do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), G0, G4_scratch, IS_ARRAY);
-
- __ profile_null_seen(G3_scratch);
- __ inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value)
- __ bind(done);
-}
-
-
-void TemplateTable::bastore() {
- transition(itos, vtos);
- __ pop_i(O2); // index
- // Otos_i: val
- // O2: index
- // O3: array
- __ index_check(O3, O2, 0, G3_scratch, O2);
- // Need to check whether array is boolean or byte
- // since both types share the bastore bytecode.
- __ load_klass(O3, G4_scratch);
- __ ld(G4_scratch, in_bytes(Klass::layout_helper_offset()), G4_scratch);
- __ set(Klass::layout_helper_boolean_diffbit(), G3_scratch);
- __ andcc(G3_scratch, G4_scratch, G0);
- Label L_skip;
- __ br(Assembler::zero, false, Assembler::pn, L_skip);
- __ delayed()->nop();
- __ and3(Otos_i, 1, Otos_i); // if it is a T_BOOLEAN array, mask the stored value to 0/1
- __ bind(L_skip);
- __ stb(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_BYTE));
-}
-
-
-void TemplateTable::castore() {
- transition(itos, vtos);
- __ pop_i(O2); // index
- // Otos_i: val
- // O3: array
- __ index_check(O3, O2, LogBytesPerShort, G3_scratch, O2);
- __ sth(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_CHAR));
-}
-
-
-void TemplateTable::sastore() {
- // %%%%% Factor across platform
- castore();
-}
-
-
-void TemplateTable::istore(int n) {
- transition(itos, vtos);
- __ st(Otos_i, Llocals, Interpreter::local_offset_in_bytes(n));
-}
-
-
-void TemplateTable::lstore(int n) {
- transition(ltos, vtos);
- assert(n+1 < Argument::n_register_parameters, "only handle register cases");
- __ store_unaligned_long(Otos_l, Llocals, Interpreter::local_offset_in_bytes(n+1));
-
-}
-
-
-void TemplateTable::fstore(int n) {
- transition(ftos, vtos);
- assert(n < Argument::n_register_parameters, "only handle register cases");
- __ stf(FloatRegisterImpl::S, Ftos_f, Llocals, Interpreter::local_offset_in_bytes(n));
-}
-
-
-void TemplateTable::dstore(int n) {
- transition(dtos, vtos);
- FloatRegister src = Ftos_d;
- __ store_unaligned_double(src, Llocals, Interpreter::local_offset_in_bytes(n+1));
-}
-
-
-void TemplateTable::astore(int n) {
- transition(vtos, vtos);
- __ load_ptr(0, Otos_i);
- __ inc(Lesp, Interpreter::stackElementSize);
- __ verify_oop_or_return_address(Otos_i, G3_scratch);
- __ store_local_ptr(n, Otos_i);
-}
-
-
-void TemplateTable::pop() {
- transition(vtos, vtos);
- __ inc(Lesp, Interpreter::stackElementSize);
-}
-
-
-void TemplateTable::pop2() {
- transition(vtos, vtos);
- __ inc(Lesp, 2 * Interpreter::stackElementSize);
-}
-
-
-void TemplateTable::dup() {
- transition(vtos, vtos);
- // stack: ..., a
- // load a and tag
- __ load_ptr(0, Otos_i);
- __ push_ptr(Otos_i);
- // stack: ..., a, a
-}
-
-
-void TemplateTable::dup_x1() {
- transition(vtos, vtos);
- // stack: ..., a, b
- __ load_ptr( 1, G3_scratch); // get a
- __ load_ptr( 0, Otos_l1); // get b
- __ store_ptr(1, Otos_l1); // put b
- __ store_ptr(0, G3_scratch); // put a - like swap
- __ push_ptr(Otos_l1); // push b
- // stack: ..., b, a, b
-}
-
-
-void TemplateTable::dup_x2() {
- transition(vtos, vtos);
- // stack: ..., a, b, c
- // get c and push on stack, reuse registers
- __ load_ptr( 0, G3_scratch); // get c
- __ push_ptr(G3_scratch); // push c with tag
- // stack: ..., a, b, c, c (c in reg) (Lesp - 4)
- // (stack offsets n+1 now)
- __ load_ptr( 3, Otos_l1); // get a
- __ store_ptr(3, G3_scratch); // put c at 3
- // stack: ..., c, b, c, c (a in reg)
- __ load_ptr( 2, G3_scratch); // get b
- __ store_ptr(2, Otos_l1); // put a at 2
- // stack: ..., c, a, c, c (b in reg)
- __ store_ptr(1, G3_scratch); // put b at 1
- // stack: ..., c, a, b, c
-}
-
-
-void TemplateTable::dup2() {
- transition(vtos, vtos);
- __ load_ptr(1, G3_scratch); // get a
- __ load_ptr(0, Otos_l1); // get b
- __ push_ptr(G3_scratch); // push a
- __ push_ptr(Otos_l1); // push b
- // stack: ..., a, b, a, b
-}
-
-
-void TemplateTable::dup2_x1() {
- transition(vtos, vtos);
- // stack: ..., a, b, c
- __ load_ptr( 1, Lscratch); // get b
- __ load_ptr( 2, Otos_l1); // get a
- __ store_ptr(2, Lscratch); // put b at a
- // stack: ..., b, b, c
- __ load_ptr( 0, G3_scratch); // get c
- __ store_ptr(1, G3_scratch); // put c at b
- // stack: ..., b, c, c
- __ store_ptr(0, Otos_l1); // put a at c
- // stack: ..., b, c, a
- __ push_ptr(Lscratch); // push b
- __ push_ptr(G3_scratch); // push c
- // stack: ..., b, c, a, b, c
-}
-
-
-// The spec says that these types can be a mixture of category 1 (1 word)
-// types and/or category 2 types (long and doubles)
-void TemplateTable::dup2_x2() {
- transition(vtos, vtos);
- // stack: ..., a, b, c, d
- __ load_ptr( 1, Lscratch); // get c
- __ load_ptr( 3, Otos_l1); // get a
- __ store_ptr(3, Lscratch); // put c at 3
- __ store_ptr(1, Otos_l1); // put a at 1
- // stack: ..., c, b, a, d
- __ load_ptr( 2, G3_scratch); // get b
- __ load_ptr( 0, Otos_l1); // get d
- __ store_ptr(0, G3_scratch); // put b at 0
- __ store_ptr(2, Otos_l1); // put d at 2
- // stack: ..., c, d, a, b
- __ push_ptr(Lscratch); // push c
- __ push_ptr(Otos_l1); // push d
- // stack: ..., c, d, a, b, c, d
-}
-
-
-void TemplateTable::swap() {
- transition(vtos, vtos);
- // stack: ..., a, b
- __ load_ptr( 1, G3_scratch); // get a
- __ load_ptr( 0, Otos_l1); // get b
- __ store_ptr(0, G3_scratch); // put b
- __ store_ptr(1, Otos_l1); // put a
- // stack: ..., b, a
-}
-
-
-void TemplateTable::iop2(Operation op) {
- transition(itos, itos);
- __ pop_i(O1);
- switch (op) {
- case add: __ add(O1, Otos_i, Otos_i); break;
- case sub: __ sub(O1, Otos_i, Otos_i); break;
- // %%%%% Mul may not exist: better to call .mul?
- case mul: __ smul(O1, Otos_i, Otos_i); break;
- case _and: __ and3(O1, Otos_i, Otos_i); break;
- case _or: __ or3(O1, Otos_i, Otos_i); break;
- case _xor: __ xor3(O1, Otos_i, Otos_i); break;
- case shl: __ sll(O1, Otos_i, Otos_i); break;
- case shr: __ sra(O1, Otos_i, Otos_i); break;
- case ushr: __ srl(O1, Otos_i, Otos_i); break;
- default: ShouldNotReachHere();
- }
-}
-
-
-void TemplateTable::lop2(Operation op) {
- transition(ltos, ltos);
- __ pop_l(O2);
- switch (op) {
- case add: __ add(O2, Otos_l, Otos_l); break;
- case sub: __ sub(O2, Otos_l, Otos_l); break;
- case _and: __ and3(O2, Otos_l, Otos_l); break;
- case _or: __ or3(O2, Otos_l, Otos_l); break;
- case _xor: __ xor3(O2, Otos_l, Otos_l); break;
- default: ShouldNotReachHere();
- }
-}
-
-
-void TemplateTable::idiv() {
- // %%%%% Later: ForSPARC/V7 call .sdiv library routine,
- // %%%%% Use ldsw...sdivx on pure V9 ABI. 64 bit safe.
-
- transition(itos, itos);
- __ pop_i(O1); // get 1st op
-
- // Y contains upper 32 bits of result, set it to 0 or all ones
- __ wry(G0);
- __ mov(~0, G3_scratch);
-
- __ tst(O1);
- Label neg;
- __ br(Assembler::negative, true, Assembler::pn, neg);
- __ delayed()->wry(G3_scratch);
- __ bind(neg);
-
- Label ok;
- __ tst(Otos_i);
- __ throw_if_not_icc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch );
-
- const int min_int = 0x80000000;
- Label regular;
- __ cmp(Otos_i, -1);
- __ br(Assembler::notEqual, false, Assembler::pt, regular);
- // Don't put set in delay slot
- // Set will turn into multiple instructions in 64 bit mode
- __ delayed()->nop();
- __ set(min_int, G4_scratch);
- Label done;
- __ cmp(O1, G4_scratch);
- __ br(Assembler::equal, true, Assembler::pt, done);
- __ delayed()->mov(O1, Otos_i); // (mov only executed if branch taken)
-
- __ bind(regular);
- __ sdiv(O1, Otos_i, Otos_i); // note: irem uses O1 after this instruction!
- __ bind(done);
-}
-
-
-void TemplateTable::irem() {
- transition(itos, itos);
- __ mov(Otos_i, O2); // save divisor
- idiv(); // %%%% Hack: exploits fact that idiv leaves dividend in O1
- __ smul(Otos_i, O2, Otos_i);
- __ sub(O1, Otos_i, Otos_i);
-}
-
-
-void TemplateTable::lmul() {
- transition(ltos, ltos);
- __ pop_l(O2);
- __ mulx(Otos_l, O2, Otos_l);
-
-}
-
-
-void TemplateTable::ldiv() {
- transition(ltos, ltos);
-
- // check for zero
- __ pop_l(O2);
- __ tst(Otos_l);
- __ throw_if_not_xcc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch);
- __ sdivx(O2, Otos_l, Otos_l);
-}
-
-
-void TemplateTable::lrem() {
- transition(ltos, ltos);
-
- // check for zero
- __ pop_l(O2);
- __ tst(Otos_l);
- __ throw_if_not_xcc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch);
- __ sdivx(O2, Otos_l, Otos_l2);
- __ mulx (Otos_l2, Otos_l, Otos_l2);
- __ sub (O2, Otos_l2, Otos_l);
-}
-
-
-void TemplateTable::lshl() {
- transition(itos, ltos); // %%%% could optimize, fill delay slot or opt for ultra
-
- __ pop_l(O2); // shift value in O2, O3
- __ sllx(O2, Otos_i, Otos_l);
-}
-
-
-void TemplateTable::lshr() {
- transition(itos, ltos); // %%%% see lshl comment
-
- __ pop_l(O2); // shift value in O2, O3
- __ srax(O2, Otos_i, Otos_l);
-}
-
-
-
-void TemplateTable::lushr() {
- transition(itos, ltos); // %%%% see lshl comment
-
- __ pop_l(O2); // shift value in O2, O3
- __ srlx(O2, Otos_i, Otos_l);
-}
-
-
-void TemplateTable::fop2(Operation op) {
- transition(ftos, ftos);
- switch (op) {
- case add: __ pop_f(F4); __ fadd(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break;
- case sub: __ pop_f(F4); __ fsub(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break;
- case mul: __ pop_f(F4); __ fmul(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break;
- case div: __ pop_f(F4); __ fdiv(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break;
- case rem:
- assert(Ftos_f == F0, "just checking");
- // LP64 calling conventions use F1, F3 for passing 2 floats
- __ pop_f(F1);
- __ fmov(FloatRegisterImpl::S, Ftos_f, F3);
- __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::frem));
- assert( Ftos_f == F0, "fix this code" );
- break;
-
- default: ShouldNotReachHere();
- }
-}
-
-
-void TemplateTable::dop2(Operation op) {
- transition(dtos, dtos);
- switch (op) {
- case add: __ pop_d(F4); __ fadd(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break;
- case sub: __ pop_d(F4); __ fsub(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break;
- case mul: __ pop_d(F4); __ fmul(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break;
- case div: __ pop_d(F4); __ fdiv(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break;
- case rem:
- // Pass arguments in D0, D2
- __ fmov(FloatRegisterImpl::D, Ftos_f, F2 );
- __ pop_d( F0 );
- __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::drem));
- assert( Ftos_d == F0, "fix this code" );
- break;
-
- default: ShouldNotReachHere();
- }
-}
-
-
-void TemplateTable::ineg() {
- transition(itos, itos);
- __ neg(Otos_i);
-}
-
-
-void TemplateTable::lneg() {
- transition(ltos, ltos);
- __ sub(G0, Otos_l, Otos_l);
-}
-
-
-void TemplateTable::fneg() {
- transition(ftos, ftos);
- __ fneg(FloatRegisterImpl::S, Ftos_f, Ftos_f);
-}
-
-
-void TemplateTable::dneg() {
- transition(dtos, dtos);
- __ fneg(FloatRegisterImpl::D, Ftos_f, Ftos_f);
-}
-
-
-void TemplateTable::iinc() {
- transition(vtos, vtos);
- locals_index(G3_scratch);
- __ ldsb(Lbcp, 2, O2); // load constant
- __ access_local_int(G3_scratch, Otos_i);
- __ add(Otos_i, O2, Otos_i);
- __ st(Otos_i, G3_scratch, 0); // access_local_int puts E.A. in G3_scratch
-}
-
-
-void TemplateTable::wide_iinc() {
- transition(vtos, vtos);
- locals_index_wide(G3_scratch);
- __ get_2_byte_integer_at_bcp( 4, O2, O3, InterpreterMacroAssembler::Signed);
- __ access_local_int(G3_scratch, Otos_i);
- __ add(Otos_i, O3, Otos_i);
- __ st(Otos_i, G3_scratch, 0); // access_local_int puts E.A. in G3_scratch
-}
-
-
-void TemplateTable::convert() {
-// %%%%% Factor this first part accross platforms
- #ifdef ASSERT
- TosState tos_in = ilgl;
- TosState tos_out = ilgl;
- switch (bytecode()) {
- case Bytecodes::_i2l: // fall through
- case Bytecodes::_i2f: // fall through
- case Bytecodes::_i2d: // fall through
- case Bytecodes::_i2b: // fall through
- case Bytecodes::_i2c: // fall through
- case Bytecodes::_i2s: tos_in = itos; break;
- case Bytecodes::_l2i: // fall through
- case Bytecodes::_l2f: // fall through
- case Bytecodes::_l2d: tos_in = ltos; break;
- case Bytecodes::_f2i: // fall through
- case Bytecodes::_f2l: // fall through
- case Bytecodes::_f2d: tos_in = ftos; break;
- case Bytecodes::_d2i: // fall through
- case Bytecodes::_d2l: // fall through
- case Bytecodes::_d2f: tos_in = dtos; break;
- default : ShouldNotReachHere();
- }
- switch (bytecode()) {
- case Bytecodes::_l2i: // fall through
- case Bytecodes::_f2i: // fall through
- case Bytecodes::_d2i: // fall through
- case Bytecodes::_i2b: // fall through
- case Bytecodes::_i2c: // fall through
- case Bytecodes::_i2s: tos_out = itos; break;
- case Bytecodes::_i2l: // fall through
- case Bytecodes::_f2l: // fall through
- case Bytecodes::_d2l: tos_out = ltos; break;
- case Bytecodes::_i2f: // fall through
- case Bytecodes::_l2f: // fall through
- case Bytecodes::_d2f: tos_out = ftos; break;
- case Bytecodes::_i2d: // fall through
- case Bytecodes::_l2d: // fall through
- case Bytecodes::_f2d: tos_out = dtos; break;
- default : ShouldNotReachHere();
- }
- transition(tos_in, tos_out);
- #endif
-
-
- // Conversion
- Label done;
- switch (bytecode()) {
- case Bytecodes::_i2l:
- // Sign extend the 32 bits
- __ sra ( Otos_i, 0, Otos_l );
- break;
-
- case Bytecodes::_i2f:
- __ st(Otos_i, __ d_tmp );
- __ ldf(FloatRegisterImpl::S, __ d_tmp, F0);
- __ fitof(FloatRegisterImpl::S, F0, Ftos_f);
- break;
-
- case Bytecodes::_i2d:
- __ st(Otos_i, __ d_tmp);
- __ ldf(FloatRegisterImpl::S, __ d_tmp, F0);
- __ fitof(FloatRegisterImpl::D, F0, Ftos_f);
- break;
-
- case Bytecodes::_i2b:
- __ sll(Otos_i, 24, Otos_i);
- __ sra(Otos_i, 24, Otos_i);
- break;
-
- case Bytecodes::_i2c:
- __ sll(Otos_i, 16, Otos_i);
- __ srl(Otos_i, 16, Otos_i);
- break;
-
- case Bytecodes::_i2s:
- __ sll(Otos_i, 16, Otos_i);
- __ sra(Otos_i, 16, Otos_i);
- break;
-
- case Bytecodes::_l2i:
- // Sign-extend into the high 32 bits
- __ sra(Otos_l, 0, Otos_i);
- break;
-
- case Bytecodes::_l2f:
- case Bytecodes::_l2d:
- __ st_long(Otos_l, __ d_tmp);
- __ ldf(FloatRegisterImpl::D, __ d_tmp, Ftos_d);
-
- if (bytecode() == Bytecodes::_l2f) {
- __ fxtof(FloatRegisterImpl::S, Ftos_d, Ftos_f);
- } else {
- __ fxtof(FloatRegisterImpl::D, Ftos_d, Ftos_d);
- }
- break;
-
- case Bytecodes::_f2i: {
- Label isNaN;
- // result must be 0 if value is NaN; test by comparing value to itself
- __ fcmp(FloatRegisterImpl::S, Assembler::fcc0, Ftos_f, Ftos_f);
- __ fb(Assembler::f_unordered, true, Assembler::pn, isNaN);
- __ delayed()->clr(Otos_i); // NaN
- __ ftoi(FloatRegisterImpl::S, Ftos_f, F30);
- __ stf(FloatRegisterImpl::S, F30, __ d_tmp);
- __ ld(__ d_tmp, Otos_i);
- __ bind(isNaN);
- }
- break;
-
- case Bytecodes::_f2l:
- // must uncache tos
- __ push_f();
- __ pop_f(F1);
- __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::f2l));
- break;
-
- case Bytecodes::_f2d:
- __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, Ftos_f, Ftos_f);
- break;
-
- case Bytecodes::_d2i:
- case Bytecodes::_d2l:
- // must uncache tos
- __ push_d();
- // LP64 calling conventions pass first double arg in D0
- __ pop_d( Ftos_d );
- __ call_VM_leaf(Lscratch,
- bytecode() == Bytecodes::_d2i
- ? CAST_FROM_FN_PTR(address, SharedRuntime::d2i)
- : CAST_FROM_FN_PTR(address, SharedRuntime::d2l));
- break;
-
- case Bytecodes::_d2f:
- __ ftof( FloatRegisterImpl::D, FloatRegisterImpl::S, Ftos_d, Ftos_f);
- break;
-
- default: ShouldNotReachHere();
- }
- __ bind(done);
-}
-
-
-void TemplateTable::lcmp() {
- transition(ltos, itos);
-
- __ pop_l(O1); // pop off value 1, value 2 is in O0
- __ lcmp( O1, Otos_l, Otos_i );
-}
-
-
-void TemplateTable::float_cmp(bool is_float, int unordered_result) {
-
- if (is_float) __ pop_f(F2);
- else __ pop_d(F2);
-
- assert(Ftos_f == F0 && Ftos_d == F0, "alias checking:");
-
- __ float_cmp( is_float, unordered_result, F2, F0, Otos_i );
-}
-
-void TemplateTable::branch(bool is_jsr, bool is_wide) {
- // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also.
- __ verify_thread();
-
- const Register O2_bumped_count = O2;
- __ profile_taken_branch(G3_scratch, O2_bumped_count);
-
- // get (wide) offset to O1_disp
- const Register O1_disp = O1;
- if (is_wide) __ get_4_byte_integer_at_bcp( 1, G4_scratch, O1_disp, InterpreterMacroAssembler::set_CC);
- else __ get_2_byte_integer_at_bcp( 1, G4_scratch, O1_disp, InterpreterMacroAssembler::Signed, InterpreterMacroAssembler::set_CC);
-
- // Handle all the JSR stuff here, then exit.
- // It's much shorter and cleaner than intermingling with the
- // non-JSR normal-branch stuff occurring below.
- if( is_jsr ) {
- // compute return address as bci in Otos_i
- __ ld_ptr(Lmethod, Method::const_offset(), G3_scratch);
- __ sub(Lbcp, G3_scratch, G3_scratch);
- __ sub(G3_scratch, in_bytes(ConstMethod::codes_offset()) - (is_wide ? 5 : 3), Otos_i);
-
- // Bump Lbcp to target of JSR
- __ add(Lbcp, O1_disp, Lbcp);
- // Push returnAddress for "ret" on stack
- __ push_ptr(Otos_i);
- // And away we go!
- __ dispatch_next(vtos, 0, true);
- return;
- }
-
- // Normal (non-jsr) branch handling
-
- // Save the current Lbcp
- const Register l_cur_bcp = Lscratch;
- __ mov( Lbcp, l_cur_bcp );
-
- bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter;
- if ( increment_invocation_counter_for_backward_branches ) {
- Label Lforward;
- // check branch direction
- __ br( Assembler::positive, false, Assembler::pn, Lforward );
- // Bump bytecode pointer by displacement (take the branch)
- __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr
-
- const Register G3_method_counters = G3_scratch;
- __ get_method_counters(Lmethod, G3_method_counters, Lforward);
-
- if (TieredCompilation) {
- Label Lno_mdo, Loverflow;
- int increment = InvocationCounter::count_increment;
- if (ProfileInterpreter) {
- // If no method data exists, go to profile_continue.
- __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch);
- __ br_null_short(G4_scratch, Assembler::pn, Lno_mdo);
-
- // Increment backedge counter in the MDO
- Address mdo_backedge_counter(G4_scratch, in_bytes(MethodData::backedge_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- Address mask(G4_scratch, in_bytes(MethodData::backedge_mask_offset()));
- __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, O0,
- (UseOnStackReplacement ? Assembler::notZero : Assembler::always), &Lforward);
- __ ba_short(Loverflow);
- }
-
- // If there's no MDO, increment counter in MethodCounters*
- __ bind(Lno_mdo);
- Address backedge_counter(G3_method_counters,
- in_bytes(MethodCounters::backedge_counter_offset()) +
- in_bytes(InvocationCounter::counter_offset()));
- Address mask(G3_method_counters, in_bytes(MethodCounters::backedge_mask_offset()));
- __ increment_mask_and_jump(backedge_counter, increment, mask, G4_scratch, O0,
- (UseOnStackReplacement ? Assembler::notZero : Assembler::always), &Lforward);
- __ bind(Loverflow);
-
- // notify point for loop, pass branch bytecode
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), l_cur_bcp);
-
- // Was an OSR adapter generated?
- // O0 = osr nmethod
- __ br_null_short(O0, Assembler::pn, Lforward);
-
- // Has the nmethod been invalidated already?
- __ ldub(O0, nmethod::state_offset(), O2);
- __ cmp_and_br_short(O2, nmethod::in_use, Assembler::notEqual, Assembler::pn, Lforward);
-
- // migrate the interpreter frame off of the stack
-
- __ mov(G2_thread, L7);
- // save nmethod
- __ mov(O0, L6);
- __ set_last_Java_frame(SP, noreg);
- __ call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), L7);
- __ reset_last_Java_frame();
- __ mov(L7, G2_thread);
-
- // move OSR nmethod to I1
- __ mov(L6, I1);
-
- // OSR buffer to I0
- __ mov(O0, I0);
-
- // remove the interpreter frame
- __ restore(I5_savedSP, 0, SP);
-
- // Jump to the osr code.
- __ ld_ptr(O1, nmethod::osr_entry_point_offset(), O2);
- __ jmp(O2, G0);
- __ delayed()->nop();
-
- } else { // not TieredCompilation
- // Update Backedge branch separately from invocations
- const Register G4_invoke_ctr = G4;
- __ increment_backedge_counter(G3_method_counters, G4_invoke_ctr, G1_scratch);
- if (ProfileInterpreter) {
- __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_method_counters, G1_scratch, Lforward);
- if (UseOnStackReplacement) {
-
- __ test_backedge_count_for_osr(O2_bumped_count, G3_method_counters, l_cur_bcp, G1_scratch);
- }
- } else {
- if (UseOnStackReplacement) {
- __ test_backedge_count_for_osr(G4_invoke_ctr, G3_method_counters, l_cur_bcp, G1_scratch);
- }
- }
- }
-
- __ bind(Lforward);
- } else
- // Bump bytecode pointer by displacement (take the branch)
- __ add( O1_disp, Lbcp, Lbcp );// add to bc addr
-
- // continue with bytecode @ target
- // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above,
- // %%%%% and changing dispatch_next to dispatch_only
- __ dispatch_next(vtos, 0, true);
-}
-
-
-// Note Condition in argument is TemplateTable::Condition
-// arg scope is within class scope
-
-void TemplateTable::if_0cmp(Condition cc) {
- // no pointers, integer only!
- transition(itos, vtos);
- // assume branch is more often taken than not (loops use backward branches)
- __ cmp( Otos_i, 0);
- __ if_cmp(ccNot(cc), false);
-}
-
-
-void TemplateTable::if_icmp(Condition cc) {
- transition(itos, vtos);
- __ pop_i(O1);
- __ cmp(O1, Otos_i);
- __ if_cmp(ccNot(cc), false);
-}
-
-
-void TemplateTable::if_nullcmp(Condition cc) {
- transition(atos, vtos);
- __ tst(Otos_i);
- __ if_cmp(ccNot(cc), true);
-}
-
-
-void TemplateTable::if_acmp(Condition cc) {
- transition(atos, vtos);
- __ pop_ptr(O1);
- __ verify_oop(O1);
- __ verify_oop(Otos_i);
- __ cmp(O1, Otos_i);
- __ if_cmp(ccNot(cc), true);
-}
-
-
-
-void TemplateTable::ret() {
- transition(vtos, vtos);
- locals_index(G3_scratch);
- __ access_local_returnAddress(G3_scratch, Otos_i);
- // Otos_i contains the bci, compute the bcp from that
-
-#ifdef ASSERT
- // jsr result was labeled as an 'itos' not an 'atos' because we cannot GC
- // the result. The return address (really a BCI) was stored with an
- // 'astore' because JVM specs claim it's a pointer-sized thing. Hence in
- // the 64-bit build the 32-bit BCI is actually in the low bits of a 64-bit
- // loaded value.
- { Label zzz ;
- __ set (65536, G3_scratch) ;
- __ cmp (Otos_i, G3_scratch) ;
- __ bp( Assembler::lessEqualUnsigned, false, Assembler::xcc, Assembler::pn, zzz);
- __ delayed()->nop();
- __ stop("BCI is in the wrong register half?");
- __ bind (zzz) ;
- }
-#endif
-
- __ profile_ret(vtos, Otos_i, G4_scratch);
-
- __ ld_ptr(Lmethod, Method::const_offset(), G3_scratch);
- __ add(G3_scratch, Otos_i, G3_scratch);
- __ add(G3_scratch, in_bytes(ConstMethod::codes_offset()), Lbcp);
- __ dispatch_next(vtos, 0, true);
-}
-
-
-void TemplateTable::wide_ret() {
- transition(vtos, vtos);
- locals_index_wide(G3_scratch);
- __ access_local_returnAddress(G3_scratch, Otos_i);
- // Otos_i contains the bci, compute the bcp from that
-
- __ profile_ret(vtos, Otos_i, G4_scratch);
-
- __ ld_ptr(Lmethod, Method::const_offset(), G3_scratch);
- __ add(G3_scratch, Otos_i, G3_scratch);
- __ add(G3_scratch, in_bytes(ConstMethod::codes_offset()), Lbcp);
- __ dispatch_next(vtos, 0, true);
-}
-
-
-void TemplateTable::tableswitch() {
- transition(itos, vtos);
- Label default_case, continue_execution;
-
- // align bcp
- __ add(Lbcp, BytesPerInt, O1);
- __ and3(O1, -BytesPerInt, O1);
- // load lo, hi
- __ ld(O1, 1 * BytesPerInt, O2); // Low Byte
- __ ld(O1, 2 * BytesPerInt, O3); // High Byte
- // Sign extend the 32 bits
- __ sra ( Otos_i, 0, Otos_i );
-
- // check against lo & hi
- __ cmp( Otos_i, O2);
- __ br( Assembler::less, false, Assembler::pn, default_case);
- __ delayed()->cmp( Otos_i, O3 );
- __ br( Assembler::greater, false, Assembler::pn, default_case);
- // lookup dispatch offset
- __ delayed()->sub(Otos_i, O2, O2);
- __ profile_switch_case(O2, O3, G3_scratch, G4_scratch);
- __ sll(O2, LogBytesPerInt, O2);
- __ add(O2, 3 * BytesPerInt, O2);
- __ ba(continue_execution);
- __ delayed()->ld(O1, O2, O2);
- // handle default
- __ bind(default_case);
- __ profile_switch_default(O3);
- __ ld(O1, 0, O2); // get default offset
- // continue execution
- __ bind(continue_execution);
- __ add(Lbcp, O2, Lbcp);
- __ dispatch_next(vtos, 0, true);
-}
-
-
-void TemplateTable::lookupswitch() {
- transition(itos, itos);
- __ stop("lookupswitch bytecode should have been rewritten");
-}
-
-void TemplateTable::fast_linearswitch() {
- transition(itos, vtos);
- Label loop_entry, loop, found, continue_execution;
- // align bcp
- __ add(Lbcp, BytesPerInt, O1);
- __ and3(O1, -BytesPerInt, O1);
- // set counter
- __ ld(O1, BytesPerInt, O2);
- __ sll(O2, LogBytesPerInt + 1, O2); // in word-pairs
- __ add(O1, 2 * BytesPerInt, O3); // set first pair addr
- __ ba(loop_entry);
- __ delayed()->add(O3, O2, O2); // counter now points past last pair
-
- // table search
- __ bind(loop);
- __ cmp(O4, Otos_i);
- __ br(Assembler::equal, true, Assembler::pn, found);
- __ delayed()->ld(O3, BytesPerInt, O4); // offset -> O4
- __ inc(O3, 2 * BytesPerInt);
-
- __ bind(loop_entry);
- __ cmp(O2, O3);
- __ brx(Assembler::greaterUnsigned, true, Assembler::pt, loop);
- __ delayed()->ld(O3, 0, O4);
-
- // default case
- __ ld(O1, 0, O4); // get default offset
- if (ProfileInterpreter) {
- __ profile_switch_default(O3);
- __ ba_short(continue_execution);
- }
-
- // entry found -> get offset
- __ bind(found);
- if (ProfileInterpreter) {
- __ sub(O3, O1, O3);
- __ sub(O3, 2*BytesPerInt, O3);
- __ srl(O3, LogBytesPerInt + 1, O3); // in word-pairs
- __ profile_switch_case(O3, O1, O2, G3_scratch);
-
- __ bind(continue_execution);
- }
- __ add(Lbcp, O4, Lbcp);
- __ dispatch_next(vtos, 0, true);
-}
-
-
-void TemplateTable::fast_binaryswitch() {
- transition(itos, vtos);
- // Implementation using the following core algorithm: (copied from Intel)
- //
- // int binary_search(int key, LookupswitchPair* array, int n) {
- // // Binary search according to "Methodik des Programmierens" by
- // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985.
- // int i = 0;
- // int j = n;
- // while (i+1 < j) {
- // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q)
- // // with Q: for all i: 0 <= i < n: key < a[i]
- // // where a stands for the array and assuming that the (inexisting)
- // // element a[n] is infinitely big.
- // int h = (i + j) >> 1;
- // // i < h < j
- // if (key < array[h].fast_match()) {
- // j = h;
- // } else {
- // i = h;
- // }
- // }
- // // R: a[i] <= key < a[i+1] or Q
- // // (i.e., if key is within array, i is the correct index)
- // return i;
- // }
-
- // register allocation
- assert(Otos_i == O0, "alias checking");
- const Register Rkey = Otos_i; // already set (tosca)
- const Register Rarray = O1;
- const Register Ri = O2;
- const Register Rj = O3;
- const Register Rh = O4;
- const Register Rscratch = O5;
-
- const int log_entry_size = 3;
- const int entry_size = 1 << log_entry_size;
-
- Label found;
- // Find Array start
- __ add(Lbcp, 3 * BytesPerInt, Rarray);
- __ and3(Rarray, -BytesPerInt, Rarray);
- // initialize i & j (in delay slot)
- __ clr( Ri );
-
- // and start
- Label entry;
- __ ba(entry);
- __ delayed()->ld( Rarray, -BytesPerInt, Rj);
- // (Rj is already in the native byte-ordering.)
-
- // binary search loop
- { Label loop;
- __ bind( loop );
- // int h = (i + j) >> 1;
- __ sra( Rh, 1, Rh );
- // if (key < array[h].fast_match()) {
- // j = h;
- // } else {
- // i = h;
- // }
- __ sll( Rh, log_entry_size, Rscratch );
- __ ld( Rarray, Rscratch, Rscratch );
- // (Rscratch is already in the native byte-ordering.)
- __ cmp( Rkey, Rscratch );
- __ movcc( Assembler::less, false, Assembler::icc, Rh, Rj ); // j = h if (key < array[h].fast_match())
- __ movcc( Assembler::greaterEqual, false, Assembler::icc, Rh, Ri ); // i = h if (key >= array[h].fast_match())
-
- // while (i+1 < j)
- __ bind( entry );
- __ add( Ri, 1, Rscratch );
- __ cmp(Rscratch, Rj);
- __ br( Assembler::less, true, Assembler::pt, loop );
- __ delayed()->add( Ri, Rj, Rh ); // start h = i + j >> 1;
- }
-
- // end of binary search, result index is i (must check again!)
- Label default_case;
- Label continue_execution;
- if (ProfileInterpreter) {
- __ mov( Ri, Rh ); // Save index in i for profiling
- }
- __ sll( Ri, log_entry_size, Ri );
- __ ld( Rarray, Ri, Rscratch );
- // (Rscratch is already in the native byte-ordering.)
- __ cmp( Rkey, Rscratch );
- __ br( Assembler::notEqual, true, Assembler::pn, default_case );
- __ delayed()->ld( Rarray, -2 * BytesPerInt, Rj ); // load default offset -> j
-
- // entry found -> j = offset
- __ inc( Ri, BytesPerInt );
- __ profile_switch_case(Rh, Rj, Rscratch, Rkey);
- __ ld( Rarray, Ri, Rj );
- // (Rj is already in the native byte-ordering.)
-
- if (ProfileInterpreter) {
- __ ba_short(continue_execution);
- }
-
- __ bind(default_case); // fall through (if not profiling)
- __ profile_switch_default(Ri);
-
- __ bind(continue_execution);
- __ add( Lbcp, Rj, Lbcp );
- __ dispatch_next(vtos, 0, true);
-}
-
-
-void TemplateTable::_return(TosState state) {
- transition(state, state);
- assert(_desc->calls_vm(), "inconsistent calls_vm information");
-
- if (_desc->bytecode() == Bytecodes::_return_register_finalizer) {
- assert(state == vtos, "only valid state");
- __ mov(G0, G3_scratch);
- __ access_local_ptr(G3_scratch, Otos_i);
- __ load_klass(Otos_i, O2);
- __ set(JVM_ACC_HAS_FINALIZER, G3);
- __ ld(O2, in_bytes(Klass::access_flags_offset()), O2);
- __ andcc(G3, O2, G0);
- Label skip_register_finalizer;
- __ br(Assembler::zero, false, Assembler::pn, skip_register_finalizer);
- __ delayed()->nop();
-
- // Call out to do finalizer registration
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), Otos_i);
-
- __ bind(skip_register_finalizer);
- }
-
- if (_desc->bytecode() != Bytecodes::_return_register_finalizer) {
- Label no_safepoint;
- __ ldx(Address(G2_thread, Thread::polling_page_offset()), G3_scratch, 0);
- __ btst(SafepointMechanism::poll_bit(), G3_scratch);
- __ br(Assembler::zero, false, Assembler::pt, no_safepoint);
- __ delayed()->nop();
- __ push(state);
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint));
- __ pop(state);
- __ bind(no_safepoint);
- }
-
- // Narrow result if state is itos but result type is smaller.
- // Need to narrow in the return bytecode rather than in generate_return_entry
- // since compiled code callers expect the result to already be narrowed.
- if (state == itos) {
- __ narrow(Otos_i);
- }
- __ remove_activation(state, /* throw_monitor_exception */ true);
-
- // The caller's SP was adjusted upon method entry to accomodate
- // the callee's non-argument locals. Undo that adjustment.
- __ ret(); // return to caller
- __ delayed()->restore(I5_savedSP, G0, SP);
-}
-
-
-// ----------------------------------------------------------------------------
-// Volatile variables demand their effects be made known to all CPU's in
-// order. Store buffers on most chips allow reads & writes to reorder; the
-// JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of
-// memory barrier (i.e., it's not sufficient that the interpreter does not
-// reorder volatile references, the hardware also must not reorder them).
-//
-// According to the new Java Memory Model (JMM):
-// (1) All volatiles are serialized wrt to each other.
-// ALSO reads & writes act as aquire & release, so:
-// (2) A read cannot let unrelated NON-volatile memory refs that happen after
-// the read float up to before the read. It's OK for non-volatile memory refs
-// that happen before the volatile read to float down below it.
-// (3) Similar a volatile write cannot let unrelated NON-volatile memory refs
-// that happen BEFORE the write float down to after the write. It's OK for
-// non-volatile memory refs that happen after the volatile write to float up
-// before it.
-//
-// We only put in barriers around volatile refs (they are expensive), not
-// _between_ memory refs (that would require us to track the flavor of the
-// previous memory refs). Requirements (2) and (3) require some barriers
-// before volatile stores and after volatile loads. These nearly cover
-// requirement (1) but miss the volatile-store-volatile-load case. This final
-// case is placed after volatile-stores although it could just as well go
-// before volatile-loads.
-void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits order_constraint) {
- // Helper function to insert a is-volatile test and memory barrier
- // All current sparc implementations run in TSO, needing only StoreLoad
- if ((order_constraint & Assembler::StoreLoad) == 0) return;
- __ membar( order_constraint );
-}
-
-// ----------------------------------------------------------------------------
-void TemplateTable::resolve_cache_and_index(int byte_no,
- Register Rcache,
- Register index,
- size_t index_size) {
- // Depends on cpCacheOop layout!
-
- Label resolved;
- Bytecodes::Code code = bytecode();
- switch (code) {
- case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
- case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
- }
-
- assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
- __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, Lbyte_code, byte_no, 1, index_size);
- __ cmp(Lbyte_code, code); // have we resolved this bytecode?
- __ br(Assembler::equal, false, Assembler::pt, resolved);
- __ delayed()->set(code, O1);
-
- address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
- // first time invocation - must resolve first
- __ call_VM(noreg, entry, O1);
- // Update registers with resolved info
- __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size);
- __ bind(resolved);
-}
-
-void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
- Register method,
- Register itable_index,
- Register flags,
- bool is_invokevirtual,
- bool is_invokevfinal,
- bool is_invokedynamic) {
- // Uses both G3_scratch and G4_scratch
- Register cache = G3_scratch;
- Register index = G4_scratch;
- assert_different_registers(cache, method, itable_index);
-
- // determine constant pool cache field offsets
- assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant");
- const int method_offset = in_bytes(
- ConstantPoolCache::base_offset() +
- ((byte_no == f2_byte)
- ? ConstantPoolCacheEntry::f2_offset()
- : ConstantPoolCacheEntry::f1_offset()
- )
- );
- const int flags_offset = in_bytes(ConstantPoolCache::base_offset() +
- ConstantPoolCacheEntry::flags_offset());
- // access constant pool cache fields
- const int index_offset = in_bytes(ConstantPoolCache::base_offset() +
- ConstantPoolCacheEntry::f2_offset());
-
- if (is_invokevfinal) {
- __ get_cache_and_index_at_bcp(cache, index, 1);
- __ ld_ptr(Address(cache, method_offset), method);
- } else {
- size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2));
- resolve_cache_and_index(byte_no, cache, index, index_size);
- __ ld_ptr(Address(cache, method_offset), method);
- }
-
- if (itable_index != noreg) {
- // pick up itable or appendix index from f2 also:
- __ ld_ptr(Address(cache, index_offset), itable_index);
- }
- __ ld_ptr(Address(cache, flags_offset), flags);
-}
-
-// The Rcache register must be set before call
-void TemplateTable::load_field_cp_cache_entry(Register Robj,
- Register Rcache,
- Register index,
- Register Roffset,
- Register Rflags,
- bool is_static) {
- assert_different_registers(Rcache, Rflags, Roffset, Lscratch);
-
- ByteSize cp_base_offset = ConstantPoolCache::base_offset();
-
- __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags);
- __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset);
- if (is_static) {
- __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f1_offset(), Robj);
- const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- __ ld_ptr( Robj, mirror_offset, Robj);
- __ resolve_oop_handle(Robj, Lscratch);
- }
-}
-
-// The registers Rcache and index expected to be set before call.
-// Correct values of the Rcache and index registers are preserved.
-void TemplateTable::jvmti_post_field_access(Register Rcache,
- Register index,
- bool is_static,
- bool has_tos) {
- ByteSize cp_base_offset = ConstantPoolCache::base_offset();
-
- if (JvmtiExport::can_post_field_access()) {
- // Check to see if a field access watch has been set before we take
- // the time to call into the VM.
- Label Label1;
- assert_different_registers(Rcache, index, G1_scratch);
- AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr());
- __ load_contents(get_field_access_count_addr, G1_scratch);
- __ cmp_and_br_short(G1_scratch, 0, Assembler::equal, Assembler::pt, Label1);
-
- __ add(Rcache, in_bytes(cp_base_offset), Rcache);
-
- if (is_static) {
- __ clr(Otos_i);
- } else {
- if (has_tos) {
- // save object pointer before call_VM() clobbers it
- __ push_ptr(Otos_i); // put object on tos where GC wants it.
- } else {
- // Load top of stack (do not pop the value off the stack);
- __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), Otos_i);
- }
- __ verify_oop(Otos_i);
- }
- // Otos_i: object pointer or NULL if static
- // Rcache: cache entry pointer
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access),
- Otos_i, Rcache);
- if (!is_static && has_tos) {
- __ pop_ptr(Otos_i); // restore object pointer
- __ verify_oop(Otos_i);
- }
- __ get_cache_and_index_at_bcp(Rcache, index, 1);
- __ bind(Label1);
- }
-}
-
-void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) {
- transition(vtos, vtos);
-
- Register Rcache = G3_scratch;
- Register index = G4_scratch;
- Register Rclass = Rcache;
- Register Roffset= G4_scratch;
- Register Rflags = G1_scratch;
- ByteSize cp_base_offset = ConstantPoolCache::base_offset();
-
- resolve_cache_and_index(byte_no, Rcache, index, sizeof(u2));
- jvmti_post_field_access(Rcache, index, is_static, false);
- load_field_cp_cache_entry(Rclass, Rcache, index, Roffset, Rflags, is_static);
-
- if (!is_static) {
- pop_and_check_object(Rclass);
- } else {
- __ verify_oop(Rclass);
- }
-
- Label exit;
-
- Assembler::Membar_mask_bits membar_bits =
- Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore);
-
- if (__ membar_has_effect(membar_bits)) {
- // Get volatile flag
- __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch);
- __ and3(Rflags, Lscratch, Lscratch);
- }
-
- Label checkVolatile;
-
- // compute field type
- Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj;
- __ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags);
- // Make sure we don't need to mask Rflags after the above shift
- ConstantPoolCacheEntry::verify_tos_state_shift();
-
- // Check atos before itos for getstatic, more likely (in Queens at least)
- __ cmp(Rflags, atos);
- __ br(Assembler::notEqual, false, Assembler::pt, notObj);
- __ delayed() ->cmp(Rflags, itos);
-
- // atos
- do_oop_load(_masm, Rclass, Roffset, 0, Otos_i, noreg);
- __ verify_oop(Otos_i);
- __ push(atos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_agetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notObj);
-
- // cmp(Rflags, itos);
- __ br(Assembler::notEqual, false, Assembler::pt, notInt);
- __ delayed() ->cmp(Rflags, ltos);
-
- // itos
- __ ld(Rclass, Roffset, Otos_i);
- __ push(itos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_igetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notInt);
-
- // cmp(Rflags, ltos);
- __ br(Assembler::notEqual, false, Assembler::pt, notLong);
- __ delayed() ->cmp(Rflags, btos);
-
- // ltos
- // load must be atomic
- __ ld_long(Rclass, Roffset, Otos_l);
- __ push(ltos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_lgetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notLong);
-
- // cmp(Rflags, btos);
- __ br(Assembler::notEqual, false, Assembler::pt, notByte);
- __ delayed() ->cmp(Rflags, ztos);
-
- // btos
- __ ldsb(Rclass, Roffset, Otos_i);
- __ push(itos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notByte);
-
- // cmp(Rflags, ztos);
- __ br(Assembler::notEqual, false, Assembler::pt, notBool);
- __ delayed() ->cmp(Rflags, ctos);
-
- // ztos
- __ ldsb(Rclass, Roffset, Otos_i);
- __ push(itos);
- if (!is_static && rc == may_rewrite) {
- // use btos rewriting, no truncating to t/f bit is needed for getfield.
- patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notBool);
-
- // cmp(Rflags, ctos);
- __ br(Assembler::notEqual, false, Assembler::pt, notChar);
- __ delayed() ->cmp(Rflags, stos);
-
- // ctos
- __ lduh(Rclass, Roffset, Otos_i);
- __ push(itos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_cgetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notChar);
-
- // cmp(Rflags, stos);
- __ br(Assembler::notEqual, false, Assembler::pt, notShort);
- __ delayed() ->cmp(Rflags, ftos);
-
- // stos
- __ ldsh(Rclass, Roffset, Otos_i);
- __ push(itos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_sgetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notShort);
-
-
- // cmp(Rflags, ftos);
- __ br(Assembler::notEqual, false, Assembler::pt, notFloat);
- __ delayed() ->tst(Lscratch);
-
- // ftos
- __ ldf(FloatRegisterImpl::S, Rclass, Roffset, Ftos_f);
- __ push(ftos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_fgetfield, G3_scratch, G4_scratch);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
-
- __ bind(notFloat);
-
-
- // dtos
- __ ldf(FloatRegisterImpl::D, Rclass, Roffset, Ftos_d);
- __ push(dtos);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_dgetfield, G3_scratch, G4_scratch);
- }
-
- __ bind(checkVolatile);
- if (__ membar_has_effect(membar_bits)) {
- // __ tst(Lscratch); executed in delay slot
- __ br(Assembler::zero, false, Assembler::pt, exit);
- __ delayed()->nop();
- volatile_barrier(membar_bits);
- }
-
- __ bind(exit);
-}
-
-void TemplateTable::getfield(int byte_no) {
- getfield_or_static(byte_no, false);
-}
-
-void TemplateTable::nofast_getfield(int byte_no) {
- getfield_or_static(byte_no, false, may_not_rewrite);
-}
-
-void TemplateTable::getstatic(int byte_no) {
- getfield_or_static(byte_no, true);
-}
-
-void TemplateTable::fast_accessfield(TosState state) {
- transition(atos, state);
- Register Rcache = G3_scratch;
- Register index = G4_scratch;
- Register Roffset = G4_scratch;
- Register Rflags = Rcache;
- ByteSize cp_base_offset = ConstantPoolCache::base_offset();
-
- __ get_cache_and_index_at_bcp(Rcache, index, 1);
- jvmti_post_field_access(Rcache, index, /*is_static*/false, /*has_tos*/true);
-
- __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset);
-
- __ null_check(Otos_i);
- __ verify_oop(Otos_i);
-
- Label exit;
-
- Assembler::Membar_mask_bits membar_bits =
- Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore);
- if (__ membar_has_effect(membar_bits)) {
- // Get volatile flag
- __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Rflags);
- __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch);
- }
-
- switch (bytecode()) {
- case Bytecodes::_fast_bgetfield:
- __ ldsb(Otos_i, Roffset, Otos_i);
- break;
- case Bytecodes::_fast_cgetfield:
- __ lduh(Otos_i, Roffset, Otos_i);
- break;
- case Bytecodes::_fast_sgetfield:
- __ ldsh(Otos_i, Roffset, Otos_i);
- break;
- case Bytecodes::_fast_igetfield:
- __ ld(Otos_i, Roffset, Otos_i);
- break;
- case Bytecodes::_fast_lgetfield:
- __ ld_long(Otos_i, Roffset, Otos_l);
- break;
- case Bytecodes::_fast_fgetfield:
- __ ldf(FloatRegisterImpl::S, Otos_i, Roffset, Ftos_f);
- break;
- case Bytecodes::_fast_dgetfield:
- __ ldf(FloatRegisterImpl::D, Otos_i, Roffset, Ftos_d);
- break;
- case Bytecodes::_fast_agetfield:
- do_oop_load(_masm, Otos_i, Roffset, 0, Otos_i, noreg);
- break;
- default:
- ShouldNotReachHere();
- }
-
- if (__ membar_has_effect(membar_bits)) {
- __ btst(Lscratch, Rflags);
- __ br(Assembler::zero, false, Assembler::pt, exit);
- __ delayed()->nop();
- volatile_barrier(membar_bits);
- __ bind(exit);
- }
-
- if (state == atos) {
- __ verify_oop(Otos_i); // does not blow flags!
- }
-}
-
-void TemplateTable::jvmti_post_fast_field_mod() {
- if (JvmtiExport::can_post_field_modification()) {
- // Check to see if a field modification watch has been set before we take
- // the time to call into the VM.
- Label done;
- AddressLiteral get_field_modification_count_addr(JvmtiExport::get_field_modification_count_addr());
- __ load_contents(get_field_modification_count_addr, G4_scratch);
- __ cmp_and_br_short(G4_scratch, 0, Assembler::equal, Assembler::pt, done);
- __ pop_ptr(G4_scratch); // copy the object pointer from tos
- __ verify_oop(G4_scratch);
- __ push_ptr(G4_scratch); // put the object pointer back on tos
- __ get_cache_entry_pointer_at_bcp(G1_scratch, G3_scratch, 1);
- // Save tos values before call_VM() clobbers them. Since we have
- // to do it for every data type, we use the saved values as the
- // jvalue object.
- switch (bytecode()) { // save tos values before call_VM() clobbers them
- case Bytecodes::_fast_aputfield: __ push_ptr(Otos_i); break;
- case Bytecodes::_fast_bputfield: // fall through
- case Bytecodes::_fast_zputfield: // fall through
- case Bytecodes::_fast_sputfield: // fall through
- case Bytecodes::_fast_cputfield: // fall through
- case Bytecodes::_fast_iputfield: __ push_i(Otos_i); break;
- case Bytecodes::_fast_dputfield: __ push_d(Ftos_d); break;
- case Bytecodes::_fast_fputfield: __ push_f(Ftos_f); break;
- // get words in right order for use as jvalue object
- case Bytecodes::_fast_lputfield: __ push_l(Otos_l); break;
- }
- // setup pointer to jvalue object
- __ mov(Lesp, G3_scratch); __ inc(G3_scratch, wordSize);
- // G4_scratch: object pointer
- // G1_scratch: cache entry pointer
- // G3_scratch: jvalue object on the stack
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), G4_scratch, G1_scratch, G3_scratch);
- switch (bytecode()) { // restore tos values
- case Bytecodes::_fast_aputfield: __ pop_ptr(Otos_i); break;
- case Bytecodes::_fast_bputfield: // fall through
- case Bytecodes::_fast_zputfield: // fall through
- case Bytecodes::_fast_sputfield: // fall through
- case Bytecodes::_fast_cputfield: // fall through
- case Bytecodes::_fast_iputfield: __ pop_i(Otos_i); break;
- case Bytecodes::_fast_dputfield: __ pop_d(Ftos_d); break;
- case Bytecodes::_fast_fputfield: __ pop_f(Ftos_f); break;
- case Bytecodes::_fast_lputfield: __ pop_l(Otos_l); break;
- }
- __ bind(done);
- }
-}
-
-// The registers Rcache and index expected to be set before call.
-// The function may destroy various registers, just not the Rcache and index registers.
-void TemplateTable::jvmti_post_field_mod(Register Rcache, Register index, bool is_static) {
- ByteSize cp_base_offset = ConstantPoolCache::base_offset();
-
- if (JvmtiExport::can_post_field_modification()) {
- // Check to see if a field modification watch has been set before we take
- // the time to call into the VM.
- Label Label1;
- assert_different_registers(Rcache, index, G1_scratch);
- AddressLiteral get_field_modification_count_addr(JvmtiExport::get_field_modification_count_addr());
- __ load_contents(get_field_modification_count_addr, G1_scratch);
- __ cmp_and_br_short(G1_scratch, 0, Assembler::zero, Assembler::pt, Label1);
-
- // The Rcache and index registers have been already set.
- // This allows to eliminate this call but the Rcache and index
- // registers must be correspondingly used after this line.
- __ get_cache_and_index_at_bcp(G1_scratch, G4_scratch, 1);
-
- __ add(G1_scratch, in_bytes(cp_base_offset), G3_scratch);
- if (is_static) {
- // Life is simple. Null out the object pointer.
- __ clr(G4_scratch);
- } else {
- Register Rflags = G1_scratch;
- // Life is harder. The stack holds the value on top, followed by the
- // object. We don't know the size of the value, though; it could be
- // one or two words depending on its type. As a result, we must find
- // the type to determine where the object is.
-
- Label two_word, valsizeknown;
- __ ld_ptr(G1_scratch, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags);
- __ mov(Lesp, G4_scratch);
- __ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags);
- // Make sure we don't need to mask Rflags after the above shift
- ConstantPoolCacheEntry::verify_tos_state_shift();
- __ cmp(Rflags, ltos);
- __ br(Assembler::equal, false, Assembler::pt, two_word);
- __ delayed()->cmp(Rflags, dtos);
- __ br(Assembler::equal, false, Assembler::pt, two_word);
- __ delayed()->nop();
- __ inc(G4_scratch, Interpreter::expr_offset_in_bytes(1));
- __ ba_short(valsizeknown);
- __ bind(two_word);
-
- __ inc(G4_scratch, Interpreter::expr_offset_in_bytes(2));
-
- __ bind(valsizeknown);
- // setup object pointer
- __ ld_ptr(G4_scratch, 0, G4_scratch);
- __ verify_oop(G4_scratch);
- }
- // setup pointer to jvalue object
- __ mov(Lesp, G1_scratch); __ inc(G1_scratch, wordSize);
- // G4_scratch: object pointer or NULL if static
- // G3_scratch: cache entry pointer
- // G1_scratch: jvalue object on the stack
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification),
- G4_scratch, G3_scratch, G1_scratch);
- __ get_cache_and_index_at_bcp(Rcache, index, 1);
- __ bind(Label1);
- }
-}
-
-void TemplateTable::pop_and_check_object(Register r) {
- __ pop_ptr(r);
- __ null_check(r); // for field access must check obj.
- __ verify_oop(r);
-}
-
-void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) {
- transition(vtos, vtos);
- Register Rcache = G3_scratch;
- Register index = G4_scratch;
- Register Rclass = Rcache;
- Register Roffset= G4_scratch;
- Register Rflags = G1_scratch;
- ByteSize cp_base_offset = ConstantPoolCache::base_offset();
-
- resolve_cache_and_index(byte_no, Rcache, index, sizeof(u2));
- jvmti_post_field_mod(Rcache, index, is_static);
- load_field_cp_cache_entry(Rclass, Rcache, index, Roffset, Rflags, is_static);
-
- Assembler::Membar_mask_bits read_bits =
- Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore);
- Assembler::Membar_mask_bits write_bits = Assembler::StoreLoad;
-
- Label notVolatile, checkVolatile, exit;
- if (__ membar_has_effect(read_bits) || __ membar_has_effect(write_bits)) {
- __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch);
- __ and3(Rflags, Lscratch, Lscratch);
-
- if (__ membar_has_effect(read_bits)) {
- __ cmp_and_br_short(Lscratch, 0, Assembler::equal, Assembler::pt, notVolatile);
- volatile_barrier(read_bits);
- __ bind(notVolatile);
- }
- }
-
- __ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags);
- // Make sure we don't need to mask Rflags after the above shift
- ConstantPoolCacheEntry::verify_tos_state_shift();
-
- // compute field type
- Label notInt, notShort, notChar, notObj, notByte, notBool, notLong, notFloat;
-
- if (is_static) {
- // putstatic with object type most likely, check that first
- __ cmp(Rflags, atos);
- __ br(Assembler::notEqual, false, Assembler::pt, notObj);
- __ delayed()->cmp(Rflags, itos);
-
- // atos
- {
- __ pop_ptr();
- __ verify_oop(Otos_i);
- do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch);
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notObj);
- // cmp(Rflags, itos);
- __ br(Assembler::notEqual, false, Assembler::pt, notInt);
- __ delayed()->cmp(Rflags, btos);
-
- // itos
- {
- __ pop_i();
- __ st(Otos_i, Rclass, Roffset);
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notInt);
- } else {
- // putfield with int type most likely, check that first
- __ cmp(Rflags, itos);
- __ br(Assembler::notEqual, false, Assembler::pt, notInt);
- __ delayed()->cmp(Rflags, atos);
-
- // itos
- {
- __ pop_i();
- pop_and_check_object(Rclass);
- __ st(Otos_i, Rclass, Roffset);
- if (rc == may_rewrite) patch_bytecode(Bytecodes::_fast_iputfield, G3_scratch, G4_scratch, true, byte_no);
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notInt);
- // cmp(Rflags, atos);
- __ br(Assembler::notEqual, false, Assembler::pt, notObj);
- __ delayed()->cmp(Rflags, btos);
-
- // atos
- {
- __ pop_ptr();
- pop_and_check_object(Rclass);
- __ verify_oop(Otos_i);
- do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch);
- if (rc == may_rewrite) patch_bytecode(Bytecodes::_fast_aputfield, G3_scratch, G4_scratch, true, byte_no);
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notObj);
- }
-
- // cmp(Rflags, btos);
- __ br(Assembler::notEqual, false, Assembler::pt, notByte);
- __ delayed()->cmp(Rflags, ztos);
-
- // btos
- {
- __ pop_i();
- if (!is_static) pop_and_check_object(Rclass);
- __ stb(Otos_i, Rclass, Roffset);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_bputfield, G3_scratch, G4_scratch, true, byte_no);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notByte);
-
- // cmp(Rflags, btos);
- __ br(Assembler::notEqual, false, Assembler::pt, notBool);
- __ delayed()->cmp(Rflags, ltos);
-
- // ztos
- {
- __ pop_i();
- if (!is_static) pop_and_check_object(Rclass);
- __ and3(Otos_i, 1, Otos_i);
- __ stb(Otos_i, Rclass, Roffset);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_zputfield, G3_scratch, G4_scratch, true, byte_no);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notBool);
- // cmp(Rflags, ltos);
- __ br(Assembler::notEqual, false, Assembler::pt, notLong);
- __ delayed()->cmp(Rflags, ctos);
-
- // ltos
- {
- __ pop_l();
- if (!is_static) pop_and_check_object(Rclass);
- __ st_long(Otos_l, Rclass, Roffset);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_lputfield, G3_scratch, G4_scratch, true, byte_no);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notLong);
- // cmp(Rflags, ctos);
- __ br(Assembler::notEqual, false, Assembler::pt, notChar);
- __ delayed()->cmp(Rflags, stos);
-
- // ctos (char)
- {
- __ pop_i();
- if (!is_static) pop_and_check_object(Rclass);
- __ sth(Otos_i, Rclass, Roffset);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_cputfield, G3_scratch, G4_scratch, true, byte_no);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notChar);
- // cmp(Rflags, stos);
- __ br(Assembler::notEqual, false, Assembler::pt, notShort);
- __ delayed()->cmp(Rflags, ftos);
-
- // stos (short)
- {
- __ pop_i();
- if (!is_static) pop_and_check_object(Rclass);
- __ sth(Otos_i, Rclass, Roffset);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_sputfield, G3_scratch, G4_scratch, true, byte_no);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notShort);
- // cmp(Rflags, ftos);
- __ br(Assembler::notZero, false, Assembler::pt, notFloat);
- __ delayed()->nop();
-
- // ftos
- {
- __ pop_f();
- if (!is_static) pop_and_check_object(Rclass);
- __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_fputfield, G3_scratch, G4_scratch, true, byte_no);
- }
- __ ba(checkVolatile);
- __ delayed()->tst(Lscratch);
- }
-
- __ bind(notFloat);
-
- // dtos
- {
- __ pop_d();
- if (!is_static) pop_and_check_object(Rclass);
- __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset);
- if (!is_static && rc == may_rewrite) {
- patch_bytecode(Bytecodes::_fast_dputfield, G3_scratch, G4_scratch, true, byte_no);
- }
- }
-
- __ bind(checkVolatile);
- __ tst(Lscratch);
-
- if (__ membar_has_effect(write_bits)) {
- // __ tst(Lscratch); in delay slot
- __ br(Assembler::zero, false, Assembler::pt, exit);
- __ delayed()->nop();
- volatile_barrier(Assembler::StoreLoad);
- __ bind(exit);
- }
-}
-
-void TemplateTable::fast_storefield(TosState state) {
- transition(state, vtos);
- Register Rcache = G3_scratch;
- Register Rclass = Rcache;
- Register Roffset= G4_scratch;
- Register Rflags = G1_scratch;
- ByteSize cp_base_offset = ConstantPoolCache::base_offset();
-
- jvmti_post_fast_field_mod();
-
- __ get_cache_and_index_at_bcp(Rcache, G4_scratch, 1);
-
- Assembler::Membar_mask_bits read_bits =
- Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore);
- Assembler::Membar_mask_bits write_bits = Assembler::StoreLoad;
-
- Label notVolatile, checkVolatile, exit;
- if (__ membar_has_effect(read_bits) || __ membar_has_effect(write_bits)) {
- __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags);
- __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch);
- __ and3(Rflags, Lscratch, Lscratch);
- if (__ membar_has_effect(read_bits)) {
- __ cmp_and_br_short(Lscratch, 0, Assembler::equal, Assembler::pt, notVolatile);
- volatile_barrier(read_bits);
- __ bind(notVolatile);
- }
- }
-
- __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset);
- pop_and_check_object(Rclass);
-
- switch (bytecode()) {
- case Bytecodes::_fast_zputfield: __ and3(Otos_i, 1, Otos_i); // fall through to bputfield
- case Bytecodes::_fast_bputfield: __ stb(Otos_i, Rclass, Roffset); break;
- case Bytecodes::_fast_cputfield: /* fall through */
- case Bytecodes::_fast_sputfield: __ sth(Otos_i, Rclass, Roffset); break;
- case Bytecodes::_fast_iputfield: __ st(Otos_i, Rclass, Roffset); break;
- case Bytecodes::_fast_lputfield: __ st_long(Otos_l, Rclass, Roffset); break;
- case Bytecodes::_fast_fputfield:
- __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset);
- break;
- case Bytecodes::_fast_dputfield:
- __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset);
- break;
- case Bytecodes::_fast_aputfield:
- do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch);
- break;
- default:
- ShouldNotReachHere();
- }
-
- if (__ membar_has_effect(write_bits)) {
- __ cmp_and_br_short(Lscratch, 0, Assembler::equal, Assembler::pt, exit);
- volatile_barrier(Assembler::StoreLoad);
- __ bind(exit);
- }
-}
-
-void TemplateTable::putfield(int byte_no) {
- putfield_or_static(byte_no, false);
-}
-
-void TemplateTable::nofast_putfield(int byte_no) {
- putfield_or_static(byte_no, false, may_not_rewrite);
-}
-
-void TemplateTable::putstatic(int byte_no) {
- putfield_or_static(byte_no, true);
-}
-
-void TemplateTable::fast_xaccess(TosState state) {
- transition(vtos, state);
- Register Rcache = G3_scratch;
- Register Roffset = G4_scratch;
- Register Rflags = G4_scratch;
- Register Rreceiver = Lscratch;
-
- __ ld_ptr(Llocals, 0, Rreceiver);
-
- // access constant pool cache (is resolved)
- __ get_cache_and_index_at_bcp(Rcache, G4_scratch, 2);
- __ ld_ptr(Rcache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset(), Roffset);
- __ add(Lbcp, 1, Lbcp); // needed to report exception at the correct bcp
-
- __ verify_oop(Rreceiver);
- __ null_check(Rreceiver);
- if (state == atos) {
- do_oop_load(_masm, Rreceiver, Roffset, 0, Otos_i, noreg);
- } else if (state == itos) {
- __ ld (Rreceiver, Roffset, Otos_i) ;
- } else if (state == ftos) {
- __ ldf(FloatRegisterImpl::S, Rreceiver, Roffset, Ftos_f);
- } else {
- ShouldNotReachHere();
- }
-
- Assembler::Membar_mask_bits membar_bits =
- Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore);
- if (__ membar_has_effect(membar_bits)) {
-
- // Get is_volatile value in Rflags and check if membar is needed
- __ ld_ptr(Rcache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset(), Rflags);
-
- // Test volatile
- Label notVolatile;
- __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch);
- __ btst(Rflags, Lscratch);
- __ br(Assembler::zero, false, Assembler::pt, notVolatile);
- __ delayed()->nop();
- volatile_barrier(membar_bits);
- __ bind(notVolatile);
- }
-
- __ interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
- __ sub(Lbcp, 1, Lbcp);
-}
-
-//----------------------------------------------------------------------------------------------------
-// Calls
-
-void TemplateTable::count_calls(Register method, Register temp) {
- // implemented elsewhere
- ShouldNotReachHere();
-}
-
-void TemplateTable::prepare_invoke(int byte_no,
- Register method, // linked method (or i-klass)
- Register ra, // return address
- Register index, // itable index, MethodType, etc.
- Register recv, // if caller wants to see it
- Register flags // if caller wants to test it
- ) {
- // determine flags
- const Bytecodes::Code code = bytecode();
- const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
- const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
- const bool is_invokehandle = code == Bytecodes::_invokehandle;
- const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
- const bool is_invokespecial = code == Bytecodes::_invokespecial;
- const bool load_receiver = (recv != noreg);
- assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), "");
- assert(recv == noreg || recv == O0, "");
- assert(flags == noreg || flags == O1, "");
-
- // setup registers & access constant pool cache
- if (recv == noreg) recv = O0;
- if (flags == noreg) flags = O1;
- const Register temp = O2;
- assert_different_registers(method, ra, index, recv, flags, temp);
-
- load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
-
- __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore
-
- // maybe push appendix to arguments
- if (is_invokedynamic || is_invokehandle) {
- Label L_no_push;
- __ set((1 << ConstantPoolCacheEntry::has_appendix_shift), temp);
- __ btst(flags, temp);
- __ br(Assembler::zero, false, Assembler::pt, L_no_push);
- __ delayed()->nop();
- // Push the appendix as a trailing parameter.
- // This must be done before we get the receiver,
- // since the parameter_size includes it.
- __ load_resolved_reference_at_index(temp, index, /*tmp*/recv);
- __ verify_oop(temp);
- __ push_ptr(temp); // push appendix (MethodType, CallSite, etc.)
- __ bind(L_no_push);
- }
-
- // load receiver if needed (after appendix is pushed so parameter size is correct)
- if (load_receiver) {
- __ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, temp); // get parameter size
- __ load_receiver(temp, recv); // __ argument_address uses Gargs but we need Lesp
- __ verify_oop(recv);
- }
-
- // compute return type
- __ srl(flags, ConstantPoolCacheEntry::tos_state_shift, ra);
- // Make sure we don't need to mask flags after the above shift
- ConstantPoolCacheEntry::verify_tos_state_shift();
- // load return address
- {
- const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
- AddressLiteral table(table_addr);
- __ set(table, temp);
- __ sll(ra, LogBytesPerWord, ra);
- __ ld_ptr(Address(temp, ra), ra);
- }
-}
-
-
-void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) {
- Register Rtemp = G4_scratch;
- Register Rcall = Rindex;
- assert_different_registers(Rcall, G5_method, Gargs, Rret);
-
- // get target Method* & entry point
- __ lookup_virtual_method(Rrecv, Rindex, G5_method);
- __ profile_arguments_type(G5_method, Rcall, Gargs, true);
- __ call_from_interpreter(Rcall, Gargs, Rret);
-}
-
-void TemplateTable::invokevirtual(int byte_no) {
- transition(vtos, vtos);
- assert(byte_no == f2_byte, "use this argument");
-
- Register Rscratch = G3_scratch;
- Register Rtemp = G4_scratch;
- Register Rret = Lscratch;
- Register O0_recv = O0;
- Label notFinal;
-
- load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Rret, true, false, false);
- __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore
-
- // Check for vfinal
- __ set((1 << ConstantPoolCacheEntry::is_vfinal_shift), G4_scratch);
- __ btst(Rret, G4_scratch);
- __ br(Assembler::zero, false, Assembler::pt, notFinal);
- __ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters
-
- if (RewriteBytecodes && !UseSharedSpaces && !DumpSharedSpaces) {
- patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp);
- }
-
- invokevfinal_helper(Rscratch, Rret);
-
- __ bind(notFinal);
-
- __ mov(G5_method, Rscratch); // better scratch register
- __ load_receiver(G4_scratch, O0_recv); // gets receiverOop
- // receiver is in O0_recv
- __ verify_oop(O0_recv);
-
- // get return address
- AddressLiteral table(Interpreter::invoke_return_entry_table());
- __ set(table, Rtemp);
- __ srl(Rret, ConstantPoolCacheEntry::tos_state_shift, Rret); // get return type
- // Make sure we don't need to mask Rret after the above shift
- ConstantPoolCacheEntry::verify_tos_state_shift();
- __ sll(Rret, LogBytesPerWord, Rret);
- __ ld_ptr(Rtemp, Rret, Rret); // get return address
-
- // get receiver klass
- __ null_check(O0_recv, oopDesc::klass_offset_in_bytes());
- __ load_klass(O0_recv, O0_recv);
- __ verify_klass_ptr(O0_recv);
-
- __ profile_virtual_call(O0_recv, O4);
-
- generate_vtable_call(O0_recv, Rscratch, Rret);
-}
-
-void TemplateTable::fast_invokevfinal(int byte_no) {
- transition(vtos, vtos);
- assert(byte_no == f2_byte, "use this argument");
-
- load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Lscratch, true,
- /*is_invokevfinal*/true, false);
- __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore
- invokevfinal_helper(G3_scratch, Lscratch);
-}
-
-void TemplateTable::invokevfinal_helper(Register Rscratch, Register Rret) {
- Register Rtemp = G4_scratch;
-
- // Load receiver from stack slot
- __ ld_ptr(G5_method, in_bytes(Method::const_offset()), G4_scratch);
- __ lduh(G4_scratch, in_bytes(ConstMethod::size_of_parameters_offset()), G4_scratch);
- __ load_receiver(G4_scratch, O0);
-
- // receiver NULL check
- __ null_check(O0);
-
- __ profile_final_call(O4);
- __ profile_arguments_type(G5_method, Rscratch, Gargs, true);
-
- // get return address
- AddressLiteral table(Interpreter::invoke_return_entry_table());
- __ set(table, Rtemp);
- __ srl(Rret, ConstantPoolCacheEntry::tos_state_shift, Rret); // get return type
- // Make sure we don't need to mask Rret after the above shift
- ConstantPoolCacheEntry::verify_tos_state_shift();
- __ sll(Rret, LogBytesPerWord, Rret);
- __ ld_ptr(Rtemp, Rret, Rret); // get return address
-
-
- // do the call
- __ call_from_interpreter(Rscratch, Gargs, Rret);
-}
-
-
-void TemplateTable::invokespecial(int byte_no) {
- transition(vtos, vtos);
- assert(byte_no == f1_byte, "use this argument");
-
- const Register Rret = Lscratch;
- const Register O0_recv = O0;
- const Register Rscratch = G3_scratch;
-
- prepare_invoke(byte_no, G5_method, Rret, noreg, O0_recv); // get receiver also for null check
- __ null_check(O0_recv);
-
- // do the call
- __ profile_call(O4);
- __ profile_arguments_type(G5_method, Rscratch, Gargs, false);
- __ call_from_interpreter(Rscratch, Gargs, Rret);
-}
-
-
-void TemplateTable::invokestatic(int byte_no) {
- transition(vtos, vtos);
- assert(byte_no == f1_byte, "use this argument");
-
- const Register Rret = Lscratch;
- const Register Rscratch = G3_scratch;
-
- prepare_invoke(byte_no, G5_method, Rret); // get f1 Method*
-
- // do the call
- __ profile_call(O4);
- __ profile_arguments_type(G5_method, Rscratch, Gargs, false);
- __ call_from_interpreter(Rscratch, Gargs, Rret);
-}
-
-void TemplateTable::invokeinterface_object_method(Register RKlass,
- Register Rcall,
- Register Rret,
- Register Rflags) {
- Register Rscratch = G4_scratch;
- Register Rindex = Lscratch;
-
- assert_different_registers(Rscratch, Rindex, Rret);
-
- Label notFinal;
-
- // Check for vfinal
- __ set((1 << ConstantPoolCacheEntry::is_vfinal_shift), Rscratch);
- __ btst(Rflags, Rscratch);
- __ br(Assembler::zero, false, Assembler::pt, notFinal);
- __ delayed()->nop();
-
- __ profile_final_call(O4);
-
- // do the call - the index (f2) contains the Method*
- assert_different_registers(G5_method, Gargs, Rcall);
- __ mov(Rindex, G5_method);
- __ profile_arguments_type(G5_method, Rcall, Gargs, true);
- __ call_from_interpreter(Rcall, Gargs, Rret);
- __ bind(notFinal);
-
- __ profile_virtual_call(RKlass, O4);
- generate_vtable_call(RKlass, Rindex, Rret);
-}
-
-
-void TemplateTable::invokeinterface(int byte_no) {
- transition(vtos, vtos);
- assert(byte_no == f1_byte, "use this argument");
-
- const Register Rinterface = G1_scratch;
- const Register Rmethod = Lscratch;
- const Register Rret = G3_scratch;
- const Register O0_recv = O0;
- const Register O1_flags = O1;
- const Register O2_Klass = O2;
- const Register Rscratch = G4_scratch;
- assert_different_registers(Rscratch, G5_method);
-
- prepare_invoke(byte_no, Rinterface, Rret, Rmethod, O0_recv, O1_flags);
-
- // First check for Object case, then private interface method,
- // then regular interface method.
-
- // get receiver klass - this is also a null check
- __ null_check(O0_recv, oopDesc::klass_offset_in_bytes());
- __ load_klass(O0_recv, O2_Klass);
-
- // Special case of invokeinterface called for virtual method of
- // java.lang.Object. See cpCache.cpp for details.
- Label notObjectMethod;
- __ set((1 << ConstantPoolCacheEntry::is_forced_virtual_shift), Rscratch);
- __ btst(O1_flags, Rscratch);
- __ br(Assembler::zero, false, Assembler::pt, notObjectMethod);
- __ delayed()->nop();
-
- invokeinterface_object_method(O2_Klass, Rinterface, Rret, O1_flags);
-
- __ bind(notObjectMethod);
-
- Label L_no_such_interface;
-
- // Check for private method invocation - indicated by vfinal
- Label notVFinal;
- {
- __ set((1 << ConstantPoolCacheEntry::is_vfinal_shift), Rscratch);
- __ btst(O1_flags, Rscratch);
- __ br(Assembler::zero, false, Assembler::pt, notVFinal);
- __ delayed()->nop();
-
- Label subtype;
- Register Rtemp = O1_flags;
- __ check_klass_subtype(O2_Klass, Rinterface, Rscratch, Rtemp, subtype);
- // If we get here the typecheck failed
- __ ba(L_no_such_interface);
- __ delayed()->nop();
- __ bind(subtype);
-
- // do the call
- Register Rcall = Rinterface;
- __ mov(Rmethod, G5_method);
- assert_different_registers(Rcall, G5_method, Gargs, Rret);
-
- __ profile_arguments_type(G5_method, Rcall, Gargs, true);
- __ profile_final_call(Rscratch);
- __ call_from_interpreter(Rcall, Gargs, Rret);
- }
- __ bind(notVFinal);
-
- Register Rtemp = O1_flags;
-
- // Receiver subtype check against REFC.
- __ lookup_interface_method(// inputs: rec. class, interface, itable index
- O2_Klass, Rinterface, noreg,
- // outputs: temp reg1, temp reg2, temp reg3
- G5_method, Rscratch, Rtemp,
- L_no_such_interface,
- /*return_method=*/false);
-
- __ profile_virtual_call(O2_Klass, O4);
-
- //
- // find entry point to call
- //
-
- // Get declaring interface class from method
- __ ld_ptr(Rmethod, Method::const_offset(), Rinterface);
- __ ld_ptr(Rinterface, ConstMethod::constants_offset(), Rinterface);
- __ ld_ptr(Rinterface, ConstantPool::pool_holder_offset_in_bytes(), Rinterface);
-
- // Get itable index from method
- const Register Rindex = G5_method;
- __ ld(Rmethod, Method::itable_index_offset(), Rindex);
- __ sub(Rindex, Method::itable_index_max, Rindex);
- __ neg(Rindex);
-
- // Preserve O2_Klass for throw_AbstractMethodErrorVerbose
- __ mov(O2_Klass, O4);
- __ lookup_interface_method(// inputs: rec. class, interface, itable index
- O4, Rinterface, Rindex,
- // outputs: method, scan temp reg, temp reg
- G5_method, Rscratch, Rtemp,
- L_no_such_interface);
-
- // Check for abstract method error.
- {
- Label ok;
- __ br_notnull_short(G5_method, Assembler::pt, ok);
- // Pass arguments for generating a verbose error message.
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodErrorVerbose),
- O2_Klass, Rmethod);
- __ should_not_reach_here();
- __ bind(ok);
- }
-
- Register Rcall = Rinterface;
- assert_different_registers(Rcall, G5_method, Gargs, Rret);
-
- __ profile_arguments_type(G5_method, Rcall, Gargs, true);
- __ call_from_interpreter(Rcall, Gargs, Rret);
-
- __ bind(L_no_such_interface);
- // Pass arguments for generating a verbose error message.
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose),
- O2_Klass, Rinterface);
- __ should_not_reach_here();
-}
-
-void TemplateTable::invokehandle(int byte_no) {
- transition(vtos, vtos);
- assert(byte_no == f1_byte, "use this argument");
-
- const Register Rret = Lscratch;
- const Register G4_mtype = G4_scratch;
- const Register O0_recv = O0;
- const Register Rscratch = G3_scratch;
-
- prepare_invoke(byte_no, G5_method, Rret, G4_mtype, O0_recv);
- __ null_check(O0_recv);
-
- // G4: MethodType object (from cpool->resolved_references[f1], if necessary)
- // G5: MH.invokeExact_MT method (from f2)
-
- // Note: G4_mtype is already pushed (if necessary) by prepare_invoke
-
- // do the call
- __ verify_oop(G4_mtype);
- __ profile_final_call(O4); // FIXME: profile the LambdaForm also
- __ profile_arguments_type(G5_method, Rscratch, Gargs, true);
- __ call_from_interpreter(Rscratch, Gargs, Rret);
-}
-
-
-void TemplateTable::invokedynamic(int byte_no) {
- transition(vtos, vtos);
- assert(byte_no == f1_byte, "use this argument");
-
- const Register Rret = Lscratch;
- const Register G4_callsite = G4_scratch;
- const Register Rscratch = G3_scratch;
-
- prepare_invoke(byte_no, G5_method, Rret, G4_callsite);
-
- // G4: CallSite object (from cpool->resolved_references[f1])
- // G5: MH.linkToCallSite method (from f2)
-
- // Note: G4_callsite is already pushed by prepare_invoke
-
- // %%% should make a type profile for any invokedynamic that takes a ref argument
- // profile this call
- __ profile_call(O4);
-
- // do the call
- __ verify_oop(G4_callsite);
- __ profile_arguments_type(G5_method, Rscratch, Gargs, false);
- __ call_from_interpreter(Rscratch, Gargs, Rret);
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Allocation
-
-void TemplateTable::_new() {
- transition(vtos, atos);
-
- Label slow_case;
- Label done;
- Label initialize_header;
- Label initialize_object; // including clearing the fields
-
- Register RallocatedObject = Otos_i;
- Register RinstanceKlass = O1;
- Register Roffset = O3;
- Register Rscratch = O4;
-
- __ get_2_byte_integer_at_bcp(1, Rscratch, Roffset, InterpreterMacroAssembler::Unsigned);
- __ get_cpool_and_tags(Rscratch, G3_scratch);
- // make sure the class we're about to instantiate has been resolved
- // This is done before loading InstanceKlass to be consistent with the order
- // how Constant Pool is updated (see ConstantPool::klass_at_put)
- __ add(G3_scratch, Array::base_offset_in_bytes(), G3_scratch);
- __ ldub(G3_scratch, Roffset, G3_scratch);
- __ cmp(G3_scratch, JVM_CONSTANT_Class);
- __ br(Assembler::notEqual, false, Assembler::pn, slow_case);
- __ delayed()->sll(Roffset, LogBytesPerWord, Roffset);
- // get InstanceKlass
- __ load_resolved_klass_at_offset(Rscratch, Roffset, RinstanceKlass);
-
- // make sure klass is fully initialized:
- __ ldub(RinstanceKlass, in_bytes(InstanceKlass::init_state_offset()), G3_scratch);
- __ cmp(G3_scratch, InstanceKlass::fully_initialized);
- __ br(Assembler::notEqual, false, Assembler::pn, slow_case);
- __ delayed()->ld(RinstanceKlass, in_bytes(Klass::layout_helper_offset()), Roffset);
-
- // get instance_size in InstanceKlass (already aligned)
- //__ ld(RinstanceKlass, in_bytes(Klass::layout_helper_offset()), Roffset);
-
- // make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class
- __ btst(Klass::_lh_instance_slow_path_bit, Roffset);
- __ br(Assembler::notZero, false, Assembler::pn, slow_case);
- __ delayed()->nop();
-
- // Allocate the instance:
- // If TLAB is enabled:
- // Try to allocate in the TLAB.
- // If fails, go to the slow path.
- // Else If inline contiguous allocations are enabled:
- // Try to allocate in eden.
- // If fails due to heap end, go to slow path.
- //
- // If TLAB is enabled OR inline contiguous is enabled:
- // Initialize the allocation.
- // Exit.
- //
- // Go to slow path.
-
- const bool allow_shared_alloc =
- Universe::heap()->supports_inline_contig_alloc();
-
- if(UseTLAB) {
- Register RoldTopValue = RallocatedObject;
- Register RtlabWasteLimitValue = G3_scratch;
- Register RnewTopValue = G1_scratch;
- Register RendValue = Rscratch;
- Register RfreeValue = RnewTopValue;
-
- // check if we can allocate in the TLAB
- __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), RoldTopValue); // sets up RalocatedObject
- __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), RendValue);
- __ add(RoldTopValue, Roffset, RnewTopValue);
-
- // if there is enough space, we do not CAS and do not clear
- __ cmp(RnewTopValue, RendValue);
- if(ZeroTLAB) {
- // the fields have already been cleared
- __ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_header);
- } else {
- // initialize both the header and fields
- __ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_object);
- }
- __ delayed()->st_ptr(RnewTopValue, G2_thread, in_bytes(JavaThread::tlab_top_offset()));
-
- // Allocation does not fit in the TLAB.
- __ ba_short(slow_case);
- } else {
- // Allocation in the shared Eden
- if (allow_shared_alloc) {
- Register RoldTopValue = G1_scratch;
- Register RtopAddr = G3_scratch;
- Register RnewTopValue = RallocatedObject;
- Register RendValue = Rscratch;
-
- __ set((intptr_t)Universe::heap()->top_addr(), RtopAddr);
-
- Label retry;
- __ bind(retry);
- __ set((intptr_t)Universe::heap()->end_addr(), RendValue);
- __ ld_ptr(RendValue, 0, RendValue);
- __ ld_ptr(RtopAddr, 0, RoldTopValue);
- __ add(RoldTopValue, Roffset, RnewTopValue);
-
- // RnewTopValue contains the top address after the new object
- // has been allocated.
- __ cmp_and_brx_short(RnewTopValue, RendValue, Assembler::greaterUnsigned, Assembler::pn, slow_case);
-
- __ cas_ptr(RtopAddr, RoldTopValue, RnewTopValue);
-
- // if someone beat us on the allocation, try again, otherwise continue
- __ cmp_and_brx_short(RoldTopValue, RnewTopValue, Assembler::notEqual, Assembler::pn, retry);
-
- // bump total bytes allocated by this thread
- // RoldTopValue and RtopAddr are dead, so can use G1 and G3
- __ incr_allocated_bytes(Roffset, G1_scratch, G3_scratch);
- }
- }
-
- // If UseTLAB or allow_shared_alloc are true, the object is created above and
- // there is an initialize need. Otherwise, skip and go to the slow path.
- if (UseTLAB || allow_shared_alloc) {
- // clear object fields
- __ bind(initialize_object);
- __ deccc(Roffset, sizeof(oopDesc));
- __ br(Assembler::zero, false, Assembler::pt, initialize_header);
- __ delayed()->add(RallocatedObject, sizeof(oopDesc), G3_scratch);
-
- // initialize remaining object fields
- if (UseBlockZeroing) {
- // Use BIS for zeroing
- __ bis_zeroing(G3_scratch, Roffset, G1_scratch, initialize_header);
- } else {
- Label loop;
- __ subcc(Roffset, wordSize, Roffset);
- __ bind(loop);
- //__ subcc(Roffset, wordSize, Roffset); // executed above loop or in delay slot
- __ st_ptr(G0, G3_scratch, Roffset);
- __ br(Assembler::notEqual, false, Assembler::pt, loop);
- __ delayed()->subcc(Roffset, wordSize, Roffset);
- }
- __ ba_short(initialize_header);
- }
-
- // slow case
- __ bind(slow_case);
- __ get_2_byte_integer_at_bcp(1, G3_scratch, O2, InterpreterMacroAssembler::Unsigned);
- __ get_constant_pool(O1);
-
- call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), O1, O2);
-
- __ ba_short(done);
-
- // Initialize the header: mark, klass
- __ bind(initialize_header);
-
- if (UseBiasedLocking) {
- __ ld_ptr(RinstanceKlass, in_bytes(Klass::prototype_header_offset()), G4_scratch);
- } else {
- __ set((intptr_t)markWord::prototype().value(), G4_scratch);
- }
- __ st_ptr(G4_scratch, RallocatedObject, oopDesc::mark_offset_in_bytes()); // mark
- __ store_klass_gap(G0, RallocatedObject); // klass gap if compressed
- __ store_klass(RinstanceKlass, RallocatedObject); // klass (last for cms)
-
- {
- SkipIfEqual skip_if(
- _masm, G4_scratch, &DTraceAllocProbes, Assembler::zero);
- // Trigger dtrace event
- __ push(atos);
- __ call_VM_leaf(noreg,
- CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), O0);
- __ pop(atos);
- }
-
- // continue
- __ bind(done);
-}
-
-
-
-void TemplateTable::newarray() {
- transition(itos, atos);
- __ ldub(Lbcp, 1, O1);
- call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), O1, Otos_i);
-}
-
-
-void TemplateTable::anewarray() {
- transition(itos, atos);
- __ get_constant_pool(O1);
- __ get_2_byte_integer_at_bcp(1, G4_scratch, O2, InterpreterMacroAssembler::Unsigned);
- call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), O1, O2, Otos_i);
-}
-
-
-void TemplateTable::arraylength() {
- transition(atos, itos);
- Label ok;
- __ verify_oop(Otos_i);
- __ tst(Otos_i);
- __ throw_if_not_1_x( Assembler::notZero, ok );
- __ delayed()->ld(Otos_i, arrayOopDesc::length_offset_in_bytes(), Otos_i);
- __ throw_if_not_2( Interpreter::_throw_NullPointerException_entry, G3_scratch, ok);
-}
-
-
-void TemplateTable::checkcast() {
- transition(atos, atos);
- Label done, is_null, quicked, cast_ok, resolved;
- Register Roffset = G1_scratch;
- Register RobjKlass = O5;
- Register RspecifiedKlass = O4;
-
- // Check for casting a NULL
- __ br_null(Otos_i, false, Assembler::pn, is_null);
- __ delayed()->nop();
-
- // Get value klass in RobjKlass
- __ load_klass(Otos_i, RobjKlass); // get value klass
-
- // Get constant pool tag
- __ get_2_byte_integer_at_bcp(1, Lscratch, Roffset, InterpreterMacroAssembler::Unsigned);
-
- // See if the checkcast has been quickened
- __ get_cpool_and_tags(Lscratch, G3_scratch);
- __ add(G3_scratch, Array::base_offset_in_bytes(), G3_scratch);
- __ ldub(G3_scratch, Roffset, G3_scratch);
- __ cmp(G3_scratch, JVM_CONSTANT_Class);
- __ br(Assembler::equal, true, Assembler::pt, quicked);
- __ delayed()->sll(Roffset, LogBytesPerWord, Roffset);
-
- __ push_ptr(); // save receiver for result, and for GC
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) );
- __ get_vm_result_2(RspecifiedKlass);
- __ pop_ptr(Otos_i, G3_scratch); // restore receiver
-
- __ ba_short(resolved);
-
- // Extract target class from constant pool
- __ bind(quicked);
- __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass);
-
-
- __ bind(resolved);
- __ load_klass(Otos_i, RobjKlass); // get value klass
-
- // Generate a fast subtype check. Branch to cast_ok if no
- // failure. Throw exception if failure.
- __ gen_subtype_check( RobjKlass, RspecifiedKlass, G3_scratch, G4_scratch, G1_scratch, cast_ok );
-
- // Not a subtype; so must throw exception
- __ throw_if_not_x( Assembler::never, Interpreter::_throw_ClassCastException_entry, G3_scratch );
-
- __ bind(cast_ok);
-
- if (ProfileInterpreter) {
- __ ba_short(done);
- }
- __ bind(is_null);
- __ profile_null_seen(G3_scratch);
- __ bind(done);
-}
-
-
-void TemplateTable::instanceof() {
- Label done, is_null, quicked, resolved;
- transition(atos, itos);
- Register Roffset = G1_scratch;
- Register RobjKlass = O5;
- Register RspecifiedKlass = O4;
-
- // Check for casting a NULL
- __ br_null(Otos_i, false, Assembler::pt, is_null);
- __ delayed()->nop();
-
- // Get value klass in RobjKlass
- __ load_klass(Otos_i, RobjKlass); // get value klass
-
- // Get constant pool tag
- __ get_2_byte_integer_at_bcp(1, Lscratch, Roffset, InterpreterMacroAssembler::Unsigned);
-
- // See if the checkcast has been quickened
- __ get_cpool_and_tags(Lscratch, G3_scratch);
- __ add(G3_scratch, Array::base_offset_in_bytes(), G3_scratch);
- __ ldub(G3_scratch, Roffset, G3_scratch);
- __ cmp(G3_scratch, JVM_CONSTANT_Class);
- __ br(Assembler::equal, true, Assembler::pt, quicked);
- __ delayed()->sll(Roffset, LogBytesPerWord, Roffset);
-
- __ push_ptr(); // save receiver for result, and for GC
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) );
- __ get_vm_result_2(RspecifiedKlass);
- __ pop_ptr(Otos_i, G3_scratch); // restore receiver
-
- __ ba_short(resolved);
-
- // Extract target class from constant pool
- __ bind(quicked);
- __ get_constant_pool(Lscratch);
- __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass);
-
- __ bind(resolved);
- __ load_klass(Otos_i, RobjKlass); // get value klass
-
- // Generate a fast subtype check. Branch to cast_ok if no
- // failure. Return 0 if failure.
- __ or3(G0, 1, Otos_i); // set result assuming quick tests succeed
- __ gen_subtype_check( RobjKlass, RspecifiedKlass, G3_scratch, G4_scratch, G1_scratch, done );
- // Not a subtype; return 0;
- __ clr( Otos_i );
-
- if (ProfileInterpreter) {
- __ ba_short(done);
- }
- __ bind(is_null);
- __ profile_null_seen(G3_scratch);
- __ bind(done);
-}
-
-void TemplateTable::_breakpoint() {
-
- // Note: We get here even if we are single stepping..
- // jbug insists on setting breakpoints at every bytecode
- // even if we are in single step mode.
-
- transition(vtos, vtos);
- // get the unpatched byte code
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), Lmethod, Lbcp);
- __ mov(O0, Lbyte_code);
-
- // post the breakpoint event
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), Lmethod, Lbcp);
-
- // complete the execution of original bytecode
- __ dispatch_normal(vtos);
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Exceptions
-
-void TemplateTable::athrow() {
- transition(atos, vtos);
-
- // This works because exception is cached in Otos_i which is same as O0,
- // which is same as what throw_exception_entry_expects
- assert(Otos_i == Oexception, "see explanation above");
-
- __ verify_oop(Otos_i);
- __ null_check(Otos_i);
- __ throw_if_not_x(Assembler::never, Interpreter::throw_exception_entry(), G3_scratch);
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Synchronization
-
-
-// See frame_sparc.hpp for monitor block layout.
-// Monitor elements are dynamically allocated by growing stack as needed.
-
-void TemplateTable::monitorenter() {
- transition(atos, vtos);
- __ verify_oop(Otos_i);
- // Try to acquire a lock on the object
- // Repeat until succeeded (i.e., until
- // monitorenter returns true).
-
- { Label ok;
- __ tst(Otos_i);
- __ throw_if_not_1_x( Assembler::notZero, ok);
- __ delayed()->mov(Otos_i, Lscratch); // save obj
- __ throw_if_not_2( Interpreter::_throw_NullPointerException_entry, G3_scratch, ok);
- }
-
- assert(O0 == Otos_i, "Be sure where the object to lock is");
-
- // find a free slot in the monitor block
-
-
- // initialize entry pointer
- __ clr(O1); // points to free slot or NULL
-
- {
- Label entry, loop, exit;
- __ add( __ top_most_monitor(), O2 ); // last one to check
- __ ba( entry );
- __ delayed()->mov( Lmonitors, O3 ); // first one to check
-
-
- __ bind( loop );
-
- __ verify_oop(O4); // verify each monitor's oop
- __ tst(O4); // is this entry unused?
- __ movcc( Assembler::zero, false, Assembler::ptr_cc, O3, O1);
-
- __ cmp(O4, O0); // check if current entry is for same object
- __ brx( Assembler::equal, false, Assembler::pn, exit );
- __ delayed()->inc( O3, frame::interpreter_frame_monitor_size() * wordSize ); // check next one
-
- __ bind( entry );
-
- __ cmp( O3, O2 );
- __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, loop );
- __ delayed()->ld_ptr(O3, BasicObjectLock::obj_offset_in_bytes(), O4);
-
- __ bind( exit );
- }
-
- { Label allocated;
-
- // found free slot?
- __ br_notnull_short(O1, Assembler::pn, allocated);
-
- __ add_monitor_to_stack( false, O2, O3 );
- __ mov(Lmonitors, O1);
-
- __ bind(allocated);
- }
-
- // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly.
- // The object has already been poped from the stack, so the expression stack looks correct.
- __ inc(Lbcp);
-
- __ st_ptr(O0, O1, BasicObjectLock::obj_offset_in_bytes()); // store object
- __ lock_object(O1, O0);
-
- // check if there's enough space on the stack for the monitors after locking
- __ generate_stack_overflow_check(0);
-
- // The bcp has already been incremented. Just need to dispatch to next instruction.
- __ dispatch_next(vtos);
-}
-
-
-void TemplateTable::monitorexit() {
- transition(atos, vtos);
- __ verify_oop(Otos_i);
- __ tst(Otos_i);
- __ throw_if_not_x( Assembler::notZero, Interpreter::_throw_NullPointerException_entry, G3_scratch );
-
- assert(O0 == Otos_i, "just checking");
-
- { Label entry, loop, found;
- __ add( __ top_most_monitor(), O2 ); // last one to check
- __ ba(entry);
- // use Lscratch to hold monitor elem to check, start with most recent monitor,
- // By using a local it survives the call to the C routine.
- __ delayed()->mov( Lmonitors, Lscratch );
-
- __ bind( loop );
-
- __ verify_oop(O4); // verify each monitor's oop
- __ cmp(O4, O0); // check if current entry is for desired object
- __ brx( Assembler::equal, true, Assembler::pt, found );
- __ delayed()->mov(Lscratch, O1); // pass found entry as argument to monitorexit
-
- __ inc( Lscratch, frame::interpreter_frame_monitor_size() * wordSize ); // advance to next
-
- __ bind( entry );
-
- __ cmp( Lscratch, O2 );
- __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, loop );
- __ delayed()->ld_ptr(Lscratch, BasicObjectLock::obj_offset_in_bytes(), O4);
-
- call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
- __ should_not_reach_here();
-
- __ bind(found);
- }
- __ unlock_object(O1);
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Wide instructions
-
-void TemplateTable::wide() {
- transition(vtos, vtos);
- __ ldub(Lbcp, 1, G3_scratch);// get next bc
- __ sll(G3_scratch, LogBytesPerWord, G3_scratch);
- AddressLiteral ep(Interpreter::_wentry_point);
- __ set(ep, G4_scratch);
- __ ld_ptr(G4_scratch, G3_scratch, G3_scratch);
- __ jmp(G3_scratch, G0);
- __ delayed()->nop();
- // Note: the Lbcp increment step is part of the individual wide bytecode implementations
-}
-
-
-//----------------------------------------------------------------------------------------------------
-// Multi arrays
-
-void TemplateTable::multianewarray() {
- transition(vtos, atos);
- // put ndims * wordSize into Lscratch
- __ ldub( Lbcp, 3, Lscratch);
- __ sll( Lscratch, Interpreter::logStackElementSize, Lscratch);
- // Lesp points past last_dim, so set to O1 to first_dim address
- __ add( Lesp, Lscratch, O1);
- call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), O1);
- __ add( Lesp, Lscratch, Lesp); // pop all dimensions off the stack
-}
diff --git a/src/hotspot/cpu/sparc/templateTable_sparc.hpp b/src/hotspot/cpu/sparc/templateTable_sparc.hpp
deleted file mode 100644
index e5c54a1bc6f..00000000000
--- a/src/hotspot/cpu/sparc/templateTable_sparc.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_TEMPLATETABLE_SPARC_HPP
-#define CPU_SPARC_TEMPLATETABLE_SPARC_HPP
-
- static void prepare_invoke(int byte_no,
- Register method, // linked method (or i-klass)
- Register ra, // return address
- Register index = noreg, // itable index, MethodType, etc.
- Register recv = noreg, // if caller wants to see it
- Register flags = noreg // if caller wants to test it
- );
- // helper function
- static void invokevfinal_helper(Register Rcache, Register Rret);
- static void invokeinterface_object_method(Register RKlass, Register Rcall,
- Register Rret,
- Register Rflags);
- static void generate_vtable_call(Register Rrecv, Register Rindex, Register Rret);
- static void volatile_barrier(Assembler::Membar_mask_bits order_constraint);
-
-#endif // CPU_SPARC_TEMPLATETABLE_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/vmStructs_sparc.hpp b/src/hotspot/cpu/sparc/vmStructs_sparc.hpp
deleted file mode 100644
index 305145d51ff..00000000000
--- a/src/hotspot/cpu/sparc/vmStructs_sparc.hpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_VMSTRUCTS_SPARC_HPP
-#define CPU_SPARC_VMSTRUCTS_SPARC_HPP
-
-// These are the CPU-specific fields, types and integer
-// constants required by the Serviceability Agent. This file is
-// referenced by vmStructs.cpp.
-
-#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- volatile_nonstatic_field(JavaFrameAnchor, _flags, int)
-
-#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
-
-#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
- /******************************/ \
- /* Register numbers (C2 only) */ \
- /******************************/ \
- \
- declare_c2_constant(R_L0_num) \
- declare_c2_constant(R_L1_num) \
- declare_c2_constant(R_L2_num) \
- declare_c2_constant(R_L3_num) \
- declare_c2_constant(R_L4_num) \
- declare_c2_constant(R_L5_num) \
- declare_c2_constant(R_L6_num) \
- declare_c2_constant(R_L7_num) \
- declare_c2_constant(R_I0_num) \
- declare_c2_constant(R_I1_num) \
- declare_c2_constant(R_I2_num) \
- declare_c2_constant(R_I3_num) \
- declare_c2_constant(R_I4_num) \
- declare_c2_constant(R_I5_num) \
- declare_c2_constant(R_FP_num) \
- declare_c2_constant(R_I7_num) \
- declare_c2_constant(R_O0_num) \
- declare_c2_constant(R_O1_num) \
- declare_c2_constant(R_O2_num) \
- declare_c2_constant(R_O3_num) \
- declare_c2_constant(R_O4_num) \
- declare_c2_constant(R_O5_num) \
- declare_c2_constant(R_SP_num) \
- declare_c2_constant(R_O7_num) \
- declare_c2_constant(R_G0_num) \
- declare_c2_constant(R_G1_num) \
- declare_c2_constant(R_G2_num) \
- declare_c2_constant(R_G3_num) \
- declare_c2_constant(R_G4_num) \
- declare_c2_constant(R_G5_num) \
- declare_c2_constant(R_G6_num) \
- declare_c2_constant(R_G7_num) \
- declare_constant(VM_Version::ISA_V9) \
- declare_constant(VM_Version::ISA_POPC) \
- declare_constant(VM_Version::ISA_VIS1) \
- declare_constant(VM_Version::ISA_VIS2) \
- declare_constant(VM_Version::ISA_BLK_INIT) \
- declare_constant(VM_Version::ISA_FMAF) \
- declare_constant(VM_Version::ISA_VIS3) \
- declare_constant(VM_Version::ISA_HPC) \
- declare_constant(VM_Version::ISA_IMA) \
- declare_constant(VM_Version::ISA_AES) \
- declare_constant(VM_Version::ISA_DES) \
- declare_constant(VM_Version::ISA_KASUMI) \
- declare_constant(VM_Version::ISA_CAMELLIA) \
- declare_constant(VM_Version::ISA_MD5) \
- declare_constant(VM_Version::ISA_SHA1) \
- declare_constant(VM_Version::ISA_SHA256) \
- declare_constant(VM_Version::ISA_SHA512) \
- declare_constant(VM_Version::ISA_MPMUL) \
- declare_constant(VM_Version::ISA_MONT) \
- declare_constant(VM_Version::ISA_PAUSE) \
- declare_constant(VM_Version::ISA_CBCOND) \
- declare_constant(VM_Version::ISA_CRC32C) \
- declare_constant(VM_Version::ISA_VIS3B) \
- declare_constant(VM_Version::ISA_ADI) \
- declare_constant(VM_Version::ISA_SPARC5) \
- declare_constant(VM_Version::ISA_MWAIT) \
- declare_constant(VM_Version::ISA_XMPMUL) \
- declare_constant(VM_Version::ISA_XMONT) \
- declare_constant(VM_Version::ISA_PAUSE_NSEC) \
- declare_constant(VM_Version::ISA_VAMASK) \
- declare_constant(VM_Version::ISA_SPARC6) \
- declare_constant(VM_Version::ISA_DICTUNP) \
- declare_constant(VM_Version::ISA_FPCMPSHL) \
- declare_constant(VM_Version::ISA_RLE) \
- declare_constant(VM_Version::ISA_SHA3) \
- declare_constant(VM_Version::ISA_VIS3C) \
- declare_constant(VM_Version::ISA_SPARC5B) \
- declare_constant(VM_Version::ISA_MME) \
- declare_constant(VM_Version::CPU_FAST_IDIV) \
- declare_constant(VM_Version::CPU_FAST_RDPC) \
- declare_constant(VM_Version::CPU_FAST_BIS) \
- declare_constant(VM_Version::CPU_FAST_LD) \
- declare_constant(VM_Version::CPU_FAST_CMOVE) \
- declare_constant(VM_Version::CPU_FAST_IND_BR) \
- declare_constant(VM_Version::CPU_BLK_ZEROING)
-
-#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-
-#endif // CPU_SPARC_VMSTRUCTS_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp b/src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp
deleted file mode 100644
index d31262a0ff5..00000000000
--- a/src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "jvm.h"
-#include "memory/allocation.hpp"
-#include "memory/allocation.inline.hpp"
-#include "vm_version_ext_sparc.hpp"
-
-// VM_Version_Ext statics
-int VM_Version_Ext::_no_of_threads = 0;
-int VM_Version_Ext::_no_of_cores = 0;
-int VM_Version_Ext::_no_of_sockets = 0;
-#if defined(SOLARIS)
-kid_t VM_Version_Ext::_kcid = -1;
-#endif
-char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0};
-char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0};
-
-#if defined(SOLARIS)
-// get cpu information. It takes into account if the kstat chain id
-// has been changed and update the info if necessary.
-bool VM_Version_Ext::initialize_cpu_information(void) {
-
- int core_id = -1;
- int chip_id = -1;
- int len = 0;
- char* src_string = NULL;
- kstat_ctl_t* kc = kstat_open();
- if (!kc) {
- return false;
- }
-
- // check if kstat chain has been updated
- kid_t kcid = kstat_chain_update(kc);
- if (kcid == -1) {
- kstat_close(kc);
- return false;
- }
-
- bool updated = ((kcid > 0) && (kcid != _kcid)) ||
- ((kcid == 0) && (_kcid == -1));
- if (!updated) {
- kstat_close(kc);
- return true;
- }
-
- // update the cached _kcid
- _kcid = kcid;
-
- // find the number of online processors
- // for modern processsors, it is also known as the
- // hardware threads.
- _no_of_threads = sysconf(_SC_NPROCESSORS_ONLN);
-
- if (_no_of_threads <= 0 ) {
- kstat_close(kc);
- return false;
- }
-
- _no_of_cores = 0;
- _no_of_sockets = 0;
-
- // loop through the kstat chain
- kstat_t* ksp = NULL;
- for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
- // only interested in "cpu_info"
- if (strcmp(ksp->ks_module, (char*)CPU_INFO) == 0) {
- if (kstat_read(kc, ksp, NULL) == -1) {
- kstat_close(kc);
- return false;
- }
- if (ksp->ks_data != NULL) {
- kstat_named_t* knm = (kstat_named_t *)ksp->ks_data;
- // loop through the number of fields in each record
- for (int i = 0; i < ksp->ks_ndata; i++) {
- // set cpu type if it hasn't been already set
- if ((strcmp((const char*)&(knm[i].name), CPU_TYPE) == 0) &&
- (_cpu_name[0] == '\0')) {
- if (knm[i].data_type == KSTAT_DATA_STRING) {
- src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]);
- } else {
- src_string = (char*)&(knm[i].value.c[0]);
- }
- len = strlen(src_string);
- if (len < CPU_TYPE_DESC_BUF_SIZE) {
- jio_snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE,
- "%s", src_string);
- }
- }
-
- // set cpu description if it hasn't been already set
- if ((strcmp((const char*)&(knm[i].name), CPU_DESCRIPTION) == 0) &&
- (_cpu_desc[0] == '\0')) {
- if (knm[i].data_type == KSTAT_DATA_STRING) {
- src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]);
- } else {
- src_string = (char*)&(knm[i].value.c[0]);
- }
- len = strlen(src_string);
- if (len < CPU_DETAILED_DESC_BUF_SIZE) {
- jio_snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE,
- "%s", src_string);
- }
- }
-
- // count the number of sockets based on the chip id
- if (strcmp((const char*)&(knm[i].name), CHIP_ID) == 0) {
- if (chip_id != knm[i].value.l) {
- chip_id = knm[i].value.l;
- _no_of_sockets++;
- }
- }
-
- // count the number of cores based on the core id
- if (strcmp((const char*)&(knm[i].name), CORE_ID) == 0) {
- if (core_id != knm[i].value.l) {
- core_id = knm[i].value.l;
- _no_of_cores++;
- }
- }
- }
- }
- }
- }
-
- kstat_close(kc);
- return true;
-}
-#elif defined(LINUX)
-// get cpu information.
-bool VM_Version_Ext::initialize_cpu_information(void) {
- // Not yet implemented.
- return false;
-}
-#endif
-
-int VM_Version_Ext::number_of_threads(void) {
- initialize_cpu_information();
- return _no_of_threads;
-}
-
-int VM_Version_Ext::number_of_cores(void) {
- initialize_cpu_information();
- return _no_of_cores;
-}
-
-int VM_Version_Ext::number_of_sockets(void) {
- initialize_cpu_information();
- return _no_of_sockets;
-}
-
-const char* VM_Version_Ext::cpu_name(void) {
- if (!initialize_cpu_information()) {
- return NULL;
- }
- char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing);
- if (NULL == tmp) {
- return NULL;
- }
- strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE);
- return tmp;
-}
-
-const char* VM_Version_Ext::cpu_description(void) {
- if (!initialize_cpu_information()) {
- return NULL;
- }
- char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing);
- if (NULL == tmp) {
- return NULL;
- }
- strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE);
- return tmp;
-}
diff --git a/src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp b/src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp
deleted file mode 100644
index ae0bb6767d5..00000000000
--- a/src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_VM_VERSION_EXT_SPARC_HPP
-#define CPU_SPARC_VM_VERSION_EXT_SPARC_HPP
-
-#include "runtime/vm_version.hpp"
-#include "utilities/macros.hpp"
-
-#if defined(SOLARIS)
-#include
-#include
-#endif
-
-#define CPU_INFO "cpu_info"
-#define CPU_TYPE "fpu_type"
-#define CPU_DESCRIPTION "implementation"
-#define CHIP_ID "chip_id"
-#define CORE_ID "core_id"
-
-class VM_Version_Ext : public VM_Version {
- private:
-
- static const size_t CPU_TYPE_DESC_BUF_SIZE = 256;
- static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096;
-
- static int _no_of_threads;
- static int _no_of_cores;
- static int _no_of_sockets;
-#if defined(SOLARIS)
- static kid_t _kcid;
-#endif
- static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE];
- static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE];
-
- static bool initialize_cpu_information(void);
-
- public:
-
- static int number_of_threads(void);
- static int number_of_cores(void);
- static int number_of_sockets(void);
-
- static const char* cpu_name(void);
- static const char* cpu_description(void);
-};
-
-#endif // CPU_SPARC_VM_VERSION_EXT_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/vm_version_sparc.cpp b/src/hotspot/cpu/sparc/vm_version_sparc.cpp
deleted file mode 100644
index c94d8e0caf1..00000000000
--- a/src/hotspot/cpu/sparc/vm_version_sparc.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "jvm.h"
-#include "asm/macroAssembler.inline.hpp"
-#include "logging/log.hpp"
-#include "logging/logStream.hpp"
-#include "memory/resourceArea.hpp"
-#include "oops/compressedOops.hpp"
-#include "runtime/java.hpp"
-#include "runtime/os.hpp"
-#include "runtime/stubCodeGenerator.hpp"
-#include "runtime/vm_version.hpp"
-
-#include
-
-uint VM_Version::_L2_data_cache_line_size = 0;
-
-void VM_Version::initialize() {
- assert(_features != 0, "System pre-initialization is not complete.");
- guarantee(VM_Version::has_v9(), "only SPARC v9 is supported");
-
- PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes();
- PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes();
- PrefetchFieldsAhead = prefetch_fields_ahead();
-
- // Allocation prefetch settings
-
- AllocatePrefetchDistance = allocate_prefetch_distance();
- AllocatePrefetchStyle = allocate_prefetch_style();
-
- intx cache_line_size = prefetch_data_size();
-
- if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) {
- AllocatePrefetchStepSize = MAX2(AllocatePrefetchStepSize, cache_line_size);
- }
-
- if (AllocatePrefetchInstr == 1) {
- if (!has_blk_init()) {
- warning("BIS instructions required for AllocatePrefetchInstr 1 unavailable");
- FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0);
- }
- if (cache_line_size <= 0) {
- warning("Cache-line size must be known for AllocatePrefetchInstr 1 to work");
- FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0);
- }
- }
-
- _supports_cx8 = true; // All SPARC V9 implementations.
- _supports_atomic_getset4 = true; // Using the 'swap' instruction.
-
- if (has_fast_ind_br() && FLAG_IS_DEFAULT(UseInlineCaches)) {
- // Indirect and direct branches are cost equivalent.
- FLAG_SET_DEFAULT(UseInlineCaches, false);
- }
- // Align loops on the proper instruction boundary to fill the instruction
- // fetch buffer.
- if (FLAG_IS_DEFAULT(OptoLoopAlignment)) {
- FLAG_SET_DEFAULT(OptoLoopAlignment, VM_Version::insn_fetch_alignment);
- }
-
- // 32-bit oops don't make sense for the 64-bit VM on SPARC since the 32-bit
- // VM has the same registers and smaller objects.
- CompressedOops::set_shift(LogMinObjAlignmentInBytes);
- CompressedKlassPointers::set_shift(LogKlassAlignmentInBytes);
-
-#ifdef COMPILER2
- if (has_fast_ind_br() && FLAG_IS_DEFAULT(UseJumpTables)) {
- // Indirect and direct branches are cost equivalent.
- FLAG_SET_DEFAULT(UseJumpTables, true);
- }
- // Entry and loop tops are aligned to fill the instruction fetch buffer.
- if (FLAG_IS_DEFAULT(InteriorEntryAlignment)) {
- FLAG_SET_DEFAULT(InteriorEntryAlignment, VM_Version::insn_fetch_alignment);
- }
- if (UseTLAB && cache_line_size > 0 &&
- FLAG_IS_DEFAULT(AllocatePrefetchInstr)) {
- if (has_fast_bis()) {
- // Use BIS instruction for TLAB allocation prefetch.
- FLAG_SET_DEFAULT(AllocatePrefetchInstr, 1);
- }
- else if (has_sparc5()) {
- // Use prefetch instruction to avoid partial RAW issue on Core C4 processors,
- // also use prefetch style 3.
- FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0);
- if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
- FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3);
- }
- }
- }
- if (AllocatePrefetchInstr == 1) {
- // Use allocation prefetch style 3 because BIS instructions require
- // aligned memory addresses.
- FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3);
- }
- if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
- if (AllocatePrefetchInstr == 0) {
- // Use different prefetch distance without BIS
- FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256);
- } else {
- // Use smaller prefetch distance with BIS
- FLAG_SET_DEFAULT(AllocatePrefetchDistance, 64);
- }
- }
-
- // We increase the number of prefetched cache lines, to use just a bit more
- // aggressive approach, when the L2-cache line size is small (32 bytes), or
- // when running on newer processor implementations, such as the Core C4.
- bool inc_prefetch = cache_line_size > 0 && (cache_line_size < 64 || has_sparc5());
-
- if (inc_prefetch) {
- // We use a factor two for small cache line sizes (as before) but a slightly
- // more conservative increase when running on more recent hardware that will
- // benefit from just a bit more aggressive prefetching.
- if (FLAG_IS_DEFAULT(AllocatePrefetchLines)) {
- const int ap_lns = AllocatePrefetchLines;
- const int ap_inc = cache_line_size < 64 ? ap_lns : (ap_lns + 1) / 2;
- FLAG_SET_ERGO(AllocatePrefetchLines, ap_lns + ap_inc);
- }
- if (FLAG_IS_DEFAULT(AllocateInstancePrefetchLines)) {
- const int ip_lns = AllocateInstancePrefetchLines;
- const int ip_inc = cache_line_size < 64 ? ip_lns : (ip_lns + 1) / 2;
- FLAG_SET_ERGO(AllocateInstancePrefetchLines, ip_lns + ip_inc);
- }
- }
-#endif /* COMPILER2 */
-
- // Use hardware population count instruction if available.
- if (has_popc()) {
- if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
- FLAG_SET_DEFAULT(UsePopCountInstruction, true);
- }
- } else if (UsePopCountInstruction) {
- warning("POPC instruction is not available on this CPU");
- FLAG_SET_DEFAULT(UsePopCountInstruction, false);
- }
-
- // Use compare and branch instructions if available.
- if (has_cbcond()) {
- if (FLAG_IS_DEFAULT(UseCBCond)) {
- FLAG_SET_DEFAULT(UseCBCond, true);
- }
- } else if (UseCBCond) {
- warning("CBCOND instruction is not available on this CPU");
- FLAG_SET_DEFAULT(UseCBCond, false);
- }
-
- // Use 'mpmul' instruction if available.
- if (has_mpmul()) {
- if (FLAG_IS_DEFAULT(UseMPMUL)) {
- FLAG_SET_DEFAULT(UseMPMUL, true);
- }
- } else if (UseMPMUL) {
- warning("MPMUL instruction is not available on this CPU");
- FLAG_SET_DEFAULT(UseMPMUL, false);
- }
-
- assert(BlockZeroingLowLimit > 0, "invalid value");
-
- if (has_blk_zeroing() && cache_line_size > 0) {
- if (FLAG_IS_DEFAULT(UseBlockZeroing)) {
- FLAG_SET_DEFAULT(UseBlockZeroing, true);
- }
- } else if (UseBlockZeroing) {
- warning("BIS zeroing instructions are not available on this CPU");
- FLAG_SET_DEFAULT(UseBlockZeroing, false);
- }
-
- assert(BlockCopyLowLimit > 0, "invalid value");
-
- if (has_blk_zeroing() && cache_line_size > 0) {
- if (FLAG_IS_DEFAULT(UseBlockCopy)) {
- FLAG_SET_DEFAULT(UseBlockCopy, true);
- }
- } else if (UseBlockCopy) {
- warning("BIS instructions are not available or expensive on this CPU");
- FLAG_SET_DEFAULT(UseBlockCopy, false);
- }
-
-#ifdef COMPILER2
- if (has_fast_rdpc() && FLAG_IS_DEFAULT(UseRDPCForConstantTableBase)) {
- FLAG_SET_DEFAULT(UseRDPCForConstantTableBase, true);
- }
-
- // Currently not supported anywhere.
- FLAG_SET_DEFAULT(UseFPUForSpilling, false);
-
- MaxVectorSize = 8;
-
- assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
-#endif
-
- assert((CodeEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
- assert((OptoLoopAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
-
- char buf[512];
- jio_snprintf(buf, sizeof(buf),
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s",
- (has_v9() ? "v9" : ""),
- (has_popc() ? ", popc" : ""),
- (has_vis1() ? ", vis1" : ""),
- (has_vis2() ? ", vis2" : ""),
- (has_blk_init() ? ", blk_init" : ""),
- (has_fmaf() ? ", fmaf" : ""),
- (has_hpc() ? ", hpc" : ""),
- (has_ima() ? ", ima" : ""),
- (has_aes() ? ", aes" : ""),
- (has_des() ? ", des" : ""),
- (has_kasumi() ? ", kas" : ""),
- (has_camellia() ? ", cam" : ""),
- (has_md5() ? ", md5" : ""),
- (has_sha1() ? ", sha1" : ""),
- (has_sha256() ? ", sha256" : ""),
- (has_sha512() ? ", sha512" : ""),
- (has_mpmul() ? ", mpmul" : ""),
- (has_mont() ? ", mont" : ""),
- (has_pause() ? ", pause" : ""),
- (has_cbcond() ? ", cbcond" : ""),
- (has_crc32c() ? ", crc32c" : ""),
-
- (has_athena_plus() ? ", athena_plus" : ""),
- (has_vis3b() ? ", vis3b" : ""),
- (has_adi() ? ", adi" : ""),
- (has_sparc5() ? ", sparc5" : ""),
- (has_mwait() ? ", mwait" : ""),
- (has_xmpmul() ? ", xmpmul" : ""),
- (has_xmont() ? ", xmont" : ""),
- (has_pause_nsec() ? ", pause_nsec" : ""),
- (has_vamask() ? ", vamask" : ""),
-
- (has_sparc6() ? ", sparc6" : ""),
- (has_dictunp() ? ", dictunp" : ""),
- (has_fpcmpshl() ? ", fpcmpshl" : ""),
- (has_rle() ? ", rle" : ""),
- (has_sha3() ? ", sha3" : ""),
- (has_athena_plus2()? ", athena_plus2" : ""),
- (has_vis3c() ? ", vis3c" : ""),
- (has_sparc5b() ? ", sparc5b" : ""),
- (has_mme() ? ", mme" : ""),
-
- (has_fast_idiv() ? ", *idiv" : ""),
- (has_fast_rdpc() ? ", *rdpc" : ""),
- (has_fast_bis() ? ", *bis" : ""),
- (has_fast_ld() ? ", *ld" : ""),
- (has_fast_cmove() ? ", *cmove" : ""),
- (has_fast_ind_br() ? ", *ind_br" : ""),
- (has_blk_zeroing() ? ", *blk_zeroing" : ""));
-
- assert(strlen(buf) >= 2, "must be");
-
- _features_string = os::strdup(buf);
-
- log_info(os, cpu)("SPARC features detected: %s", _features_string);
-
- // UseVIS is set to the smallest of what hardware supports and what the command
- // line requires, i.e. you cannot set UseVIS to 3 on older UltraSparc which do
- // not support it.
-
- if (UseVIS > 3) UseVIS = 3;
- if (UseVIS < 0) UseVIS = 0;
- if (!has_vis3()) // Drop to 2 if no VIS3 support
- UseVIS = MIN2((intx)2, UseVIS);
- if (!has_vis2()) // Drop to 1 if no VIS2 support
- UseVIS = MIN2((intx)1, UseVIS);
- if (!has_vis1()) // Drop to 0 if no VIS1 support
- UseVIS = 0;
-
- if (has_aes()) {
- if (FLAG_IS_DEFAULT(UseAES)) {
- FLAG_SET_DEFAULT(UseAES, true);
- }
- if (!UseAES) {
- if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
- warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
- }
- FLAG_SET_DEFAULT(UseAESIntrinsics, false);
- } else {
- // The AES intrinsic stubs require AES instruction support (of course)
- // but also require VIS3 mode or higher for instructions it use.
- if (UseVIS > 2) {
- if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
- FLAG_SET_DEFAULT(UseAESIntrinsics, true);
- }
- } else {
- if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
- warning("SPARC AES intrinsics require VIS3 instructions. Intrinsics will be disabled.");
- }
- FLAG_SET_DEFAULT(UseAESIntrinsics, false);
- }
- }
- } else if (UseAES || UseAESIntrinsics) {
- if (UseAES && !FLAG_IS_DEFAULT(UseAES)) {
- warning("AES instructions are not available on this CPU");
- FLAG_SET_DEFAULT(UseAES, false);
- }
- if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
- warning("AES intrinsics are not available on this CPU");
- FLAG_SET_DEFAULT(UseAESIntrinsics, false);
- }
- }
-
- if (UseAESCTRIntrinsics) {
- warning("AES/CTR intrinsics are not available on this CPU");
- FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
- }
-
- // GHASH/GCM intrinsics
- if (has_vis3() && (UseVIS > 2)) {
- if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) {
- UseGHASHIntrinsics = true;
- }
- } else if (UseGHASHIntrinsics) {
- if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics))
- warning("GHASH intrinsics require VIS3 instruction support. Intrinsics will be disabled");
- FLAG_SET_DEFAULT(UseGHASHIntrinsics, false);
- }
-
- if (has_fmaf()) {
- if (FLAG_IS_DEFAULT(UseFMA)) {
- UseFMA = true;
- }
- } else if (UseFMA) {
- warning("FMA instructions are not available on this CPU");
- FLAG_SET_DEFAULT(UseFMA, false);
- }
-
- // SHA1, SHA256, and SHA512 instructions were added to SPARC at different times
- if (has_sha1() || has_sha256() || has_sha512()) {
- if (UseVIS > 0) { // SHA intrinsics use VIS1 instructions
- if (FLAG_IS_DEFAULT(UseSHA)) {
- FLAG_SET_DEFAULT(UseSHA, true);
- }
- } else {
- if (UseSHA) {
- warning("SPARC SHA intrinsics require VIS1 instruction support. Intrinsics will be disabled.");
- FLAG_SET_DEFAULT(UseSHA, false);
- }
- }
- } else if (UseSHA) {
- warning("SHA instructions are not available on this CPU");
- FLAG_SET_DEFAULT(UseSHA, false);
- }
-
- if (UseSHA && has_sha1()) {
- if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
- FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
- }
- } else if (UseSHA1Intrinsics) {
- warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
- FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
- }
-
- if (UseSHA && has_sha256()) {
- if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
- FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
- }
- } else if (UseSHA256Intrinsics) {
- warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
- FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
- }
-
- if (UseSHA && has_sha512()) {
- if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
- FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
- }
- } else if (UseSHA512Intrinsics) {
- warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
- FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
- }
-
- if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) {
- FLAG_SET_DEFAULT(UseSHA, false);
- }
-
- if (has_crc32c()) {
- if (UseVIS > 2) { // CRC32C intrinsics use VIS3 instructions
- if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
- FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
- }
- } else {
- if (UseCRC32CIntrinsics) {
- warning("SPARC CRC32C intrinsics require VIS3 instruction support. Intrinsics will be disabled.");
- FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
- }
- }
- } else if (UseCRC32CIntrinsics) {
- warning("CRC32C instruction is not available on this CPU");
- FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
- }
-
- if (UseVIS > 2) {
- if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) {
- FLAG_SET_DEFAULT(UseAdler32Intrinsics, true);
- }
- } else if (UseAdler32Intrinsics) {
- warning("SPARC Adler32 intrinsics require VIS3 instruction support. Intrinsics will be disabled.");
- FLAG_SET_DEFAULT(UseAdler32Intrinsics, false);
- }
-
- if (UseVIS > 2) {
- if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
- FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
- }
- } else if (UseCRC32Intrinsics) {
- warning("SPARC CRC32 intrinsics require VIS3 instructions support. Intrinsics will be disabled");
- FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
- }
-
- if (UseVIS > 2) {
- if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
- FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true);
- }
- } else if (UseMultiplyToLenIntrinsic) {
- warning("SPARC multiplyToLen intrinsics require VIS3 instructions support. Intrinsics will be disabled");
- FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
- }
-
- if (UseVectorizedMismatchIntrinsic) {
- warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU.");
- FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
- }
-
- if (FLAG_IS_DEFAULT(ContendedPaddingWidth) &&
- (cache_line_size > ContendedPaddingWidth))
- ContendedPaddingWidth = cache_line_size;
-
- // This machine does not allow unaligned memory accesses
- if (UseUnalignedAccesses) {
- if (!FLAG_IS_DEFAULT(UseUnalignedAccesses))
- warning("Unaligned memory access is not available on this CPU");
- FLAG_SET_DEFAULT(UseUnalignedAccesses, false);
- }
-
- if (log_is_enabled(Info, os, cpu)) {
- ResourceMark rm;
- LogStream ls(Log(os, cpu)::info());
- outputStream* log = &ls;
- log->print_cr("L1 data cache line size: %u", L1_data_cache_line_size());
- log->print_cr("L2 data cache line size: %u", L2_data_cache_line_size());
- log->print("Allocation");
- if (AllocatePrefetchStyle <= 0) {
- log->print(": no prefetching");
- } else {
- log->print(" prefetching: ");
- if (AllocatePrefetchInstr == 0) {
- log->print("PREFETCH");
- } else if (AllocatePrefetchInstr == 1) {
- log->print("BIS");
- }
- if (AllocatePrefetchLines > 1) {
- log->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize);
- } else {
- log->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize);
- }
- }
- if (PrefetchCopyIntervalInBytes > 0) {
- log->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes);
- }
- if (PrefetchScanIntervalInBytes > 0) {
- log->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes);
- }
- if (PrefetchFieldsAhead > 0) {
- log->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead);
- }
- if (ContendedPaddingWidth > 0) {
- log->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth);
- }
- }
-}
-
-void VM_Version::print_features() {
- tty->print("ISA features [0x%0" PRIx64 "]:", _features);
- if (_features_string != NULL) {
- tty->print(" %s", _features_string);
- }
- tty->cr();
-}
-
-void VM_Version::determine_features() {
- platform_features(); // platform_features() is os_arch specific.
-
- assert(has_v9(), "must be");
-
- if (UseNiagaraInstrs) { // Limit code generation to Niagara.
- _features &= niagara1_msk;
- }
-}
-
-static uint64_t saved_features = 0;
-
-void VM_Version::allow_all() {
- saved_features = _features;
- _features = full_feature_msk;
-}
-
-void VM_Version::revert() {
- _features = saved_features;
-}
diff --git a/src/hotspot/cpu/sparc/vm_version_sparc.hpp b/src/hotspot/cpu/sparc/vm_version_sparc.hpp
deleted file mode 100644
index a27ad0fb69f..00000000000
--- a/src/hotspot/cpu/sparc/vm_version_sparc.hpp
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_VM_VERSION_SPARC_HPP
-#define CPU_SPARC_VM_VERSION_SPARC_HPP
-
-#include "runtime/abstract_vm_version.hpp"
-#include "runtime/globals_extension.hpp"
-
-class VM_Version: public Abstract_VM_Version {
- friend class VMStructs;
- friend class JVMCIVMStructs;
-
-protected:
- enum {
- ISA_V9,
- ISA_POPC,
- ISA_VIS1,
- ISA_VIS2,
- ISA_BLK_INIT,
- ISA_FMAF,
- ISA_VIS3,
- ISA_HPC,
- ISA_IMA,
- ISA_AES,
- ISA_DES,
- ISA_KASUMI,
- ISA_CAMELLIA,
- ISA_MD5,
- ISA_SHA1,
- ISA_SHA256,
- ISA_SHA512,
- ISA_MPMUL,
- ISA_MONT,
- ISA_PAUSE,
- ISA_CBCOND,
- ISA_CRC32C,
-
- ISA_FJATHPLUS,
- ISA_VIS3B,
- ISA_ADI,
- ISA_SPARC5,
- ISA_MWAIT,
- ISA_XMPMUL,
- ISA_XMONT,
- ISA_PAUSE_NSEC,
- ISA_VAMASK,
-
- ISA_SPARC6,
- ISA_DICTUNP,
- ISA_FPCMPSHL,
- ISA_RLE,
- ISA_SHA3,
- ISA_FJATHPLUS2,
- ISA_VIS3C,
- ISA_SPARC5B,
- ISA_MME,
-
- // Synthesised properties:
-
- CPU_FAST_IDIV,
- CPU_FAST_RDPC,
- CPU_FAST_BIS,
- CPU_FAST_LD,
- CPU_FAST_CMOVE,
- CPU_FAST_IND_BR,
- CPU_BLK_ZEROING
- };
-
-private:
- enum { ISA_last_feature = ISA_MME,
- CPU_last_feature = CPU_BLK_ZEROING };
-
- enum {
- ISA_unknown_msk = 0,
-
- ISA_v9_msk = UINT64_C(1) << ISA_V9,
-
- ISA_popc_msk = UINT64_C(1) << ISA_POPC,
- ISA_vis1_msk = UINT64_C(1) << ISA_VIS1,
- ISA_vis2_msk = UINT64_C(1) << ISA_VIS2,
- ISA_blk_init_msk = UINT64_C(1) << ISA_BLK_INIT,
- ISA_fmaf_msk = UINT64_C(1) << ISA_FMAF,
- ISA_vis3_msk = UINT64_C(1) << ISA_VIS3,
- ISA_hpc_msk = UINT64_C(1) << ISA_HPC,
- ISA_ima_msk = UINT64_C(1) << ISA_IMA,
- ISA_aes_msk = UINT64_C(1) << ISA_AES,
- ISA_des_msk = UINT64_C(1) << ISA_DES,
- ISA_kasumi_msk = UINT64_C(1) << ISA_KASUMI,
- ISA_camellia_msk = UINT64_C(1) << ISA_CAMELLIA,
- ISA_md5_msk = UINT64_C(1) << ISA_MD5,
- ISA_sha1_msk = UINT64_C(1) << ISA_SHA1,
- ISA_sha256_msk = UINT64_C(1) << ISA_SHA256,
- ISA_sha512_msk = UINT64_C(1) << ISA_SHA512,
- ISA_mpmul_msk = UINT64_C(1) << ISA_MPMUL,
- ISA_mont_msk = UINT64_C(1) << ISA_MONT,
- ISA_pause_msk = UINT64_C(1) << ISA_PAUSE,
- ISA_cbcond_msk = UINT64_C(1) << ISA_CBCOND,
- ISA_crc32c_msk = UINT64_C(1) << ISA_CRC32C,
-
- ISA_fjathplus_msk = UINT64_C(1) << ISA_FJATHPLUS,
- ISA_vis3b_msk = UINT64_C(1) << ISA_VIS3B,
- ISA_adi_msk = UINT64_C(1) << ISA_ADI,
- ISA_sparc5_msk = UINT64_C(1) << ISA_SPARC5,
- ISA_mwait_msk = UINT64_C(1) << ISA_MWAIT,
- ISA_xmpmul_msk = UINT64_C(1) << ISA_XMPMUL,
- ISA_xmont_msk = UINT64_C(1) << ISA_XMONT,
- ISA_pause_nsec_msk = UINT64_C(1) << ISA_PAUSE_NSEC,
- ISA_vamask_msk = UINT64_C(1) << ISA_VAMASK,
-
- ISA_sparc6_msk = UINT64_C(1) << ISA_SPARC6,
- ISA_dictunp_msk = UINT64_C(1) << ISA_DICTUNP,
- ISA_fpcmpshl_msk = UINT64_C(1) << ISA_FPCMPSHL,
- ISA_rle_msk = UINT64_C(1) << ISA_RLE,
- ISA_sha3_msk = UINT64_C(1) << ISA_SHA3,
- ISA_fjathplus2_msk = UINT64_C(1) << ISA_FJATHPLUS2,
- ISA_vis3c_msk = UINT64_C(1) << ISA_VIS3C,
- ISA_sparc5b_msk = UINT64_C(1) << ISA_SPARC5B,
- ISA_mme_msk = UINT64_C(1) << ISA_MME,
-
- CPU_fast_idiv_msk = UINT64_C(1) << CPU_FAST_IDIV,
- CPU_fast_rdpc_msk = UINT64_C(1) << CPU_FAST_RDPC,
- CPU_fast_bis_msk = UINT64_C(1) << CPU_FAST_BIS,
- CPU_fast_ld_msk = UINT64_C(1) << CPU_FAST_LD,
- CPU_fast_cmove_msk = UINT64_C(1) << CPU_FAST_CMOVE,
- CPU_fast_ind_br_msk = UINT64_C(1) << CPU_FAST_IND_BR,
- CPU_blk_zeroing_msk = UINT64_C(1) << CPU_BLK_ZEROING,
-
- last_feature_msk = CPU_blk_zeroing_msk,
- full_feature_msk = (last_feature_msk << 1) - 1
- };
-
-/* The following, previously supported, SPARC implementations are no longer
- * supported.
- *
- * UltraSPARC I/II:
- * SPARC-V9, VIS
- * UltraSPARC III/+: (Cheetah/+)
- * SPARC-V9, VIS
- * UltraSPARC IV: (Jaguar)
- * SPARC-V9, VIS
- * UltraSPARC IV+: (Panther)
- * SPARC-V9, VIS, POPC
- *
- * The currently supported SPARC implementations are listed below (including
- * generic V9 support).
- *
- * UltraSPARC T1: (Niagara)
- * SPARC-V9, VIS, ASI_BIS (Crypto/hash in SPU)
- * UltraSPARC T2: (Niagara-2)
- * SPARC-V9, VIS, ASI_BIS, POPC (Crypto/hash in SPU)
- * UltraSPARC T2+: (Victoria Falls, etc.)
- * SPARC-V9, VIS, VIS2, ASI_BIS, POPC (Crypto/hash in SPU)
- *
- * UltraSPARC T3: (Rainbow Falls/C2)
- * SPARC-V9, VIS, VIS2, ASI_BIS, POPC (Crypto/hash in SPU)
- *
- * Oracle SPARC T4/T5/M5: (Core C3)
- * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND,
- * AES, DES, Kasumi, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL
- *
- * Oracle SPARC M7: (Core C4)
- * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND,
- * AES, DES, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL, VIS3b,
- * ADI, SPARC5, MWAIT, XMPMUL, XMONT, PAUSE_NSEC, VAMASK
- *
- * Oracle SPARC M8: (Core C5)
- * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND,
- * AES, DES, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL, VIS3b,
- * ADI, SPARC5, MWAIT, XMPMUL, XMONT, PAUSE_NSEC, VAMASK, SPARC6, FPCMPSHL,
- * DICTUNP, RLE, SHA3, MME
- *
- * NOTE: Oracle Number support ignored.
- */
- enum {
- niagara1_msk = ISA_v9_msk | ISA_vis1_msk | ISA_blk_init_msk,
- niagara2_msk = niagara1_msk | ISA_popc_msk,
-
- core_C2_msk = niagara2_msk | ISA_vis2_msk,
-
- core_C3_msk = core_C2_msk | ISA_fmaf_msk | ISA_vis3_msk | ISA_hpc_msk |
- ISA_ima_msk | ISA_aes_msk | ISA_des_msk | ISA_kasumi_msk |
- ISA_camellia_msk | ISA_md5_msk | ISA_sha1_msk | ISA_sha256_msk |
- ISA_sha512_msk | ISA_mpmul_msk | ISA_mont_msk | ISA_pause_msk |
- ISA_cbcond_msk | ISA_crc32c_msk,
-
- core_C4_msk = core_C3_msk - ISA_kasumi_msk |
- ISA_vis3b_msk | ISA_adi_msk | ISA_sparc5_msk | ISA_mwait_msk |
- ISA_xmpmul_msk | ISA_xmont_msk | ISA_pause_nsec_msk | ISA_vamask_msk,
-
- core_C5_msk = core_C4_msk | ISA_sparc6_msk | ISA_dictunp_msk |
- ISA_fpcmpshl_msk | ISA_rle_msk | ISA_sha3_msk | ISA_mme_msk,
-
- ultra_sparc_t1_msk = niagara1_msk,
- ultra_sparc_t2_msk = niagara2_msk,
- ultra_sparc_t3_msk = core_C2_msk,
- ultra_sparc_m5_msk = core_C3_msk, // NOTE: First out-of-order pipeline.
- ultra_sparc_m7_msk = core_C4_msk,
- ultra_sparc_m8_msk = core_C5_msk
- };
-
- static uint _L2_data_cache_line_size;
- static uint L2_data_cache_line_size() { return _L2_data_cache_line_size; }
-
- static void determine_features();
- static void platform_features();
- static void print_features();
-
-public:
- enum {
- // Adopt a conservative behaviour (modelling single-insn-fetch-n-issue) for
- // Niagara (and SPARC64). While there are at least two entries/slots in the
- // instruction fetch buffer on any Niagara core (and as many as eight on a
- // SPARC64), the performance improvement from keeping hot branch targets on
- // optimally aligned addresses is such a small one (if any) that we choose
- // not to use the extra code space required.
-
- insn_fetch_alignment = 4 // Byte alignment in L1 insn. cache.
- };
-
- static void initialize();
-
- static void init_before_ergo() { determine_features(); }
-
- // Instruction feature support:
-
- static bool has_v9() { return (_features & ISA_v9_msk) != 0; }
- static bool has_popc() { return (_features & ISA_popc_msk) != 0; }
- static bool has_vis1() { return (_features & ISA_vis1_msk) != 0; }
- static bool has_vis2() { return (_features & ISA_vis2_msk) != 0; }
- static bool has_blk_init() { return (_features & ISA_blk_init_msk) != 0; }
- static bool has_fmaf() { return (_features & ISA_fmaf_msk) != 0; }
- static bool has_vis3() { return (_features & ISA_vis3_msk) != 0; }
- static bool has_hpc() { return (_features & ISA_hpc_msk) != 0; }
- static bool has_ima() { return (_features & ISA_ima_msk) != 0; }
- static bool has_aes() { return (_features & ISA_aes_msk) != 0; }
- static bool has_des() { return (_features & ISA_des_msk) != 0; }
- static bool has_kasumi() { return (_features & ISA_kasumi_msk) != 0; }
- static bool has_camellia() { return (_features & ISA_camellia_msk) != 0; }
- static bool has_md5() { return (_features & ISA_md5_msk) != 0; }
- static bool has_sha1() { return (_features & ISA_sha1_msk) != 0; }
- static bool has_sha256() { return (_features & ISA_sha256_msk) != 0; }
- static bool has_sha512() { return (_features & ISA_sha512_msk) != 0; }
- static bool has_mpmul() { return (_features & ISA_mpmul_msk) != 0; }
- static bool has_mont() { return (_features & ISA_mont_msk) != 0; }
- static bool has_pause() { return (_features & ISA_pause_msk) != 0; }
- static bool has_cbcond() { return (_features & ISA_cbcond_msk) != 0; }
- static bool has_crc32c() { return (_features & ISA_crc32c_msk) != 0; }
-
- static bool has_athena_plus() { return (_features & ISA_fjathplus_msk) != 0; }
- static bool has_vis3b() { return (_features & ISA_vis3b_msk) != 0; }
- static bool has_adi() { return (_features & ISA_adi_msk) != 0; }
- static bool has_sparc5() { return (_features & ISA_sparc5_msk) != 0; }
- static bool has_mwait() { return (_features & ISA_mwait_msk) != 0; }
- static bool has_xmpmul() { return (_features & ISA_xmpmul_msk) != 0; }
- static bool has_xmont() { return (_features & ISA_xmont_msk) != 0; }
- static bool has_pause_nsec() { return (_features & ISA_pause_nsec_msk) != 0; }
- static bool has_vamask() { return (_features & ISA_vamask_msk) != 0; }
-
- static bool has_sparc6() { return (_features & ISA_sparc6_msk) != 0; }
- static bool has_dictunp() { return (_features & ISA_dictunp_msk) != 0; }
- static bool has_fpcmpshl() { return (_features & ISA_fpcmpshl_msk) != 0; }
- static bool has_rle() { return (_features & ISA_rle_msk) != 0; }
- static bool has_sha3() { return (_features & ISA_sha3_msk) != 0; }
- static bool has_athena_plus2() { return (_features & ISA_fjathplus2_msk) != 0; }
- static bool has_vis3c() { return (_features & ISA_vis3c_msk) != 0; }
- static bool has_sparc5b() { return (_features & ISA_sparc5b_msk) != 0; }
- static bool has_mme() { return (_features & ISA_mme_msk) != 0; }
-
- static bool has_fast_idiv() { return (_features & CPU_fast_idiv_msk) != 0; }
- static bool has_fast_rdpc() { return (_features & CPU_fast_rdpc_msk) != 0; }
- static bool has_fast_bis() { return (_features & CPU_fast_bis_msk) != 0; }
- static bool has_fast_ld() { return (_features & CPU_fast_ld_msk) != 0; }
- static bool has_fast_cmove() { return (_features & CPU_fast_cmove_msk) != 0; }
-
- // If indirect and direct branching is equally fast.
- static bool has_fast_ind_br() { return (_features & CPU_fast_ind_br_msk) != 0; }
- // If SPARC BIS to the beginning of cache line always zeros it.
- static bool has_blk_zeroing() { return (_features & CPU_blk_zeroing_msk) != 0; }
-
- static bool supports_compare_and_exchange() { return true; }
-
- // FIXME: To be removed.
- static bool is_post_niagara() {
- return (_features & niagara2_msk) == niagara2_msk;
- }
-
- // Default prefetch block size on SPARC.
- static uint prefetch_data_size() { return L2_data_cache_line_size(); }
-
- private:
- // Prefetch policy and characteristics:
- //
- // These support routines are used in order to isolate any CPU/core specific
- // logic from the actual flag/option processing. They should reflect the HW
- // characteristics for the associated options on the current platform.
- //
- // The three Prefetch* options below (assigned -1 in the configuration) are
- // treated according to (given the accepted range [-1..]):
- // -1: Determine a proper HW-specific value for the current HW.
- // 0: Off
- // >0: Command-line supplied value to use.
- //
- // FIXME: The documentation string in the configuration is wrong, saying that
- // -1 is also interpreted as off.
- //
- static intx prefetch_copy_interval_in_bytes() {
- intx bytes = PrefetchCopyIntervalInBytes;
- return bytes < 0 ? 512 : bytes;
- }
- static intx prefetch_scan_interval_in_bytes() {
- intx bytes = PrefetchScanIntervalInBytes;
- return bytes < 0 ? 512 : bytes;
- }
- static intx prefetch_fields_ahead() {
- intx count = PrefetchFieldsAhead;
- return count < 0 ? 0 : count;
- }
-
- // AllocatePrefetchDistance is treated under the same interpretation as the
- // Prefetch* options above (i.e., -1, 0, >0).
- static intx allocate_prefetch_distance() {
- intx count = AllocatePrefetchDistance;
- return count < 0 ? 512 : count;
- }
-
- // AllocatePrefetchStyle is guaranteed to be in range [0..3] defined by the
- // configuration.
- static intx allocate_prefetch_style() {
- intx distance = allocate_prefetch_distance();
- // Return 0 (off/none) if AllocatePrefetchDistance was not defined.
- return distance > 0 ? AllocatePrefetchStyle : 0;
- }
-
- public:
- // Assembler testing
- static void allow_all();
- static void revert();
-
- // Override the Abstract_VM_Version implementation.
- //
- // FIXME: Removed broken test on sun4v (always false when invoked prior to the
- // proper capability setup), thus always returning 2. Still need to fix
- // this properly in order to enable complete page size support.
- static uint page_size_count() { return 2; }
-
- // Override default denominator for ParallelGCThreads.
- //
- // FIXME: Simply checking the processor family is insufficient.
- static uint parallel_worker_threads_denominator() {
- return is_post_niagara() ? 16 : 8;
- }
-};
-
-#endif // CPU_SPARC_VM_VERSION_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/vmreg_sparc.cpp b/src/hotspot/cpu/sparc/vmreg_sparc.cpp
deleted file mode 100644
index c261a5dd09f..00000000000
--- a/src/hotspot/cpu/sparc/vmreg_sparc.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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/vmreg.hpp"
-
-
-
-void VMRegImpl::set_regName() {
- Register reg = ::as_Register(0);
- int i;
- for (i = 0; i < ConcreteRegisterImpl::max_gpr ; ) {
- regName[i++ ] = reg->name();
- regName[i++ ] = reg->name();
- reg = reg->successor();
- }
-
- FloatRegister freg = ::as_FloatRegister(0);
- for ( ; i < ConcreteRegisterImpl::max_fpr ; ) {
- regName[i++] = freg->name();
- if (freg->encoding() > 31) {
- regName[i++] = freg->name();
- }
- freg = freg->successor();
- }
-
- for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) {
- regName[i] = "NON-GPR-FPR";
- }
-}
diff --git a/src/hotspot/cpu/sparc/vmreg_sparc.hpp b/src/hotspot/cpu/sparc/vmreg_sparc.hpp
deleted file mode 100644
index 2eefe37cbd4..00000000000
--- a/src/hotspot/cpu/sparc/vmreg_sparc.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_VMREG_SPARC_HPP
-#define CPU_SPARC_VMREG_SPARC_HPP
-
-inline bool is_Register() { return value() >= 0 && value() < ConcreteRegisterImpl::max_gpr; }
-inline bool is_FloatRegister() { return value() >= ConcreteRegisterImpl::max_gpr &&
- value() < ConcreteRegisterImpl::max_fpr; }
-inline Register as_Register() {
- assert( is_Register() && is_even(value()), "even-aligned GPR name" );
- // Yuk
- return ::as_Register(value()>>1);
-}
-
-inline FloatRegister as_FloatRegister() {
- assert( is_FloatRegister(), "must be" );
- // Yuk
- return ::as_FloatRegister( value() - ConcreteRegisterImpl::max_gpr );
-}
-
-inline bool is_concrete() {
- assert(is_reg(), "must be");
- int v = value();
- if ( v < ConcreteRegisterImpl::max_gpr ) {
- return is_even(v);
- }
- // F0..F31
- if ( v <= ConcreteRegisterImpl::max_gpr + 31) return true;
- if ( v < ConcreteRegisterImpl::max_fpr) {
- return is_even(v);
- }
- assert(false, "what register?");
- return false;
-}
-
-#endif // CPU_SPARC_VMREG_SPARC_HPP
diff --git a/src/hotspot/cpu/sparc/vmreg_sparc.inline.hpp b/src/hotspot/cpu/sparc/vmreg_sparc.inline.hpp
deleted file mode 100644
index 26f402742a1..00000000000
--- a/src/hotspot/cpu/sparc/vmreg_sparc.inline.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef CPU_SPARC_VMREG_SPARC_INLINE_HPP
-#define CPU_SPARC_VMREG_SPARC_INLINE_HPP
-
-inline VMReg RegisterImpl::as_VMReg() {
- if( this==noreg ) return VMRegImpl::Bad();
- return VMRegImpl::as_VMReg(encoding() << 1 );
-}
-
-inline VMReg FloatRegisterImpl::as_VMReg() { return VMRegImpl::as_VMReg( ConcreteRegisterImpl::max_gpr + encoding() ); }
-
-
-
-#endif // CPU_SPARC_VMREG_SPARC_INLINE_HPP
diff --git a/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp b/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp
deleted file mode 100644
index 1b4d30524a1..00000000000
--- a/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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/vtableStubs.hpp"
-#include "interp_masm_sparc.hpp"
-#include "memory/resourceArea.hpp"
-#include "oops/compiledICHolder.hpp"
-#include "oops/instanceKlass.hpp"
-#include "oops/klassVtable.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "vmreg_sparc.inline.hpp"
-#ifdef COMPILER2
-#include "opto/runtime.hpp"
-#endif
-
-// machine-dependent part of VtableStubs: create vtableStub of correct size and
-// initialize its code
-
-#define __ masm->
-
-#ifndef PRODUCT
-extern "C" void bad_compiled_vtable_index(JavaThread* thread, oopDesc* receiver, int index);
-#endif
-
-
-// Used by compiler only; may use only caller saved, non-argument registers
-VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
- // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing.
- const int stub_code_length = code_size_limit(true);
- VtableStub* s = new(stub_code_length) VtableStub(true, vtable_index);
- // Can be NULL if there is no free space in the code cache.
- if (s == NULL) {
- return NULL;
- }
-
- // Count unused bytes in instruction sequences of variable size.
- // We add them to the computed buffer size in order to avoid
- // overflow in subsequently generated stubs.
- address start_pc;
- int slop_bytes = 0;
- int slop_delta = 0;
- const int index_dependent_slop = ((vtable_index < 512) ? 2 : 0)*BytesPerInstWord; // code size change with transition from 13-bit to 32-bit constant (@index == 512?).
-
- ResourceMark rm;
- CodeBuffer cb(s->entry_point(), stub_code_length);
- MacroAssembler* masm = new MacroAssembler(&cb);
-
-#if (!defined(PRODUCT) && defined(COMPILER2))
- if (CountCompiledCalls) {
- __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), G5, G3_scratch);
- }
-#endif // PRODUCT
-
- assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0");
-
- // get receiver klass
- address npe_addr = __ pc();
- __ load_klass(O0, G3_scratch);
-
-#ifndef PRODUCT
- if (DebugVtables) {
- Label L;
- // check offset vs vtable length
- __ ld(G3_scratch, in_bytes(Klass::vtable_length_offset()), G5);
- __ cmp_and_br_short(G5, vtable_index*vtableEntry::size(), Assembler::greaterUnsigned, Assembler::pt, L);
-
- // set generates 8 instructions (worst case), 1 instruction (best case)
- start_pc = __ pc();
- __ set(vtable_index, O2);
- slop_delta = __ worst_case_insts_for_set()*BytesPerInstWord - (__ pc() - start_pc);
- slop_bytes += slop_delta;
- assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta);
-
- // there is no variance in call_VM() emitted code.
- __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), O0, O2);
- __ bind(L);
- }
-#endif
-
- // set Method* (in case of interpreted method), and destination address
- start_pc = __ pc();
- __ lookup_virtual_method(G3_scratch, vtable_index, G5_method);
- // lookup_virtual_method generates 3 instructions (worst case), 1 instruction (best case)
- slop_delta = 3*BytesPerInstWord - (int)(__ pc() - start_pc);
- slop_bytes += slop_delta;
- assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta);
-
-#ifndef PRODUCT
- if (DebugVtables) {
- Label L;
- __ br_notnull_short(G5_method, Assembler::pt, L);
- __ stop("Vtable entry is ZERO");
- __ bind(L);
- }
-#endif
-
- address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract
- // NOTE: for vtable dispatches, the vtable entry will never be null.
-
- __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch);
-
- // jump to target (either compiled code or c2iadapter)
- __ JMP(G3_scratch, 0);
- // load Method* (in case we call c2iadapter)
- __ delayed()->nop();
-
- masm->flush();
- slop_bytes += index_dependent_slop; // add'l slop for size variance due to large itable offsets
- bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, index_dependent_slop);
-
- return s;
-}
-
-
-VtableStub* VtableStubs::create_itable_stub(int itable_index) {
- // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing.
- const int stub_code_length = code_size_limit(false);
- VtableStub* s = new(stub_code_length) VtableStub(false, itable_index);
- // Can be NULL if there is no free space in the code cache.
- if (s == NULL) {
- return NULL;
- }
- // Count unused bytes in instruction sequences of variable size.
- // We add them to the computed buffer size in order to avoid
- // overflow in subsequently generated stubs.
- address start_pc;
- int slop_bytes = 0;
- int slop_delta = 0;
- const int index_dependent_slop = ((itable_index < 512) ? 2 : 0)*BytesPerInstWord; // code size change with transition from 13-bit to 32-bit constant (@index == 512?).
-
- ResourceMark rm;
- CodeBuffer cb(s->entry_point(), stub_code_length);
- MacroAssembler* masm = new MacroAssembler(&cb);
-
-#if (!defined(PRODUCT) && defined(COMPILER2))
- if (CountCompiledCalls) {
-// Use G3_scratch, G4_scratch as work regs for inc_counter.
-// These are defined before use further down.
- __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), G3_scratch, G4_scratch);
- }
-#endif // PRODUCT
-
- Register G3_Klass = G3_scratch;
- Register G5_icholder = G5; // Passed in as an argument
- Register G4_interface = G4_scratch;
-
- // Entry arguments:
- // G5_interface: Interface
- // O0: Receiver
- assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0");
-
- // get receiver klass (also an implicit null-check)
- address npe_addr = __ pc();
- __ load_klass(O0, G3_Klass);
-
- // Push a new window to get some temp registers. This chops the head of all
- // my 64-bit %o registers in the LION build, but this is OK because no longs
- // are passed in the %o registers. Instead, longs are passed in G1 and G4
- // and so those registers are not available here.
- __ save(SP,-frame::register_save_words*wordSize,SP);
-
- Label L_no_such_interface;
- Register L5_method = L5;
-
- start_pc = __ pc();
-
- // Receiver subtype check against REFC.
- __ ld_ptr(G5_icholder, CompiledICHolder::holder_klass_offset(), G4_interface);
- __ lookup_interface_method(// inputs: rec. class, interface, itable index
- G3_Klass, G4_interface, itable_index,
- // outputs: scan temp. reg1, scan temp. reg2
- L5_method, L2, L3,
- L_no_such_interface,
- /*return_method=*/ false);
-
- const ptrdiff_t typecheckSize = __ pc() - start_pc;
- start_pc = __ pc();
-
- // Get Method* and entrypoint for compiler
- __ ld_ptr(G5_icholder, CompiledICHolder::holder_metadata_offset(), G4_interface);
- __ lookup_interface_method(// inputs: rec. class, interface, itable index
- G3_Klass, G4_interface, itable_index,
- // outputs: method, scan temp. reg
- L5_method, L2, L3,
- L_no_such_interface);
-
- const ptrdiff_t lookupSize = __ pc() - start_pc;
-
- // Reduce "estimate" such that "padding" does not drop below 8.
- // Do not target a left-over number of zero, because a very
- // large vtable or itable offset (> 4K) will require an extra
- // sethi/or pair of instructions.
- // Found typecheck(60) + lookup(72) to exceed previous extimate (32*4).
- const ptrdiff_t estimate = 36*BytesPerInstWord;
- const ptrdiff_t codesize = typecheckSize + lookupSize + index_dependent_slop;
- slop_delta = (int)(estimate - codesize);
- slop_bytes += slop_delta;
- assert(slop_delta >= 0, "itable #%d: Code size estimate (%d) for lookup_interface_method too small, required: %d", itable_index, (int)estimate, (int)codesize);
-
-#ifndef PRODUCT
- if (DebugVtables) {
- Label L01;
- __ br_notnull_short(L5_method, Assembler::pt, L01);
- __ stop("Method* is null");
- __ bind(L01);
- }
-#endif
-
- // If the following load is through a NULL pointer, we'll take an OS
- // exception that should translate into an AbstractMethodError. We need the
- // window count to be correct at that time.
- __ restore(L5_method, 0, G5_method);
- // Restore registers *before* the AME point.
-
- address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract
- __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch);
-
- // G5_method: Method*
- // O0: Receiver
- // G3_scratch: entry point
- __ JMP(G3_scratch, 0);
- __ delayed()->nop();
-
- __ bind(L_no_such_interface);
- // Handle IncompatibleClassChangeError in itable stubs.
- // More detailed error message.
- // We force resolving of the call site by jumping to the "handle
- // wrong method" stub, and so let the interpreter runtime do all the
- // dirty work.
- AddressLiteral icce(SharedRuntime::get_handle_wrong_method_stub());
- __ jump_to(icce, G3_scratch);
- __ delayed()->restore();
-
- masm->flush();
- slop_bytes += index_dependent_slop; // add'l slop for size variance due to large itable offsets
- bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, index_dependent_slop);
-
- return s;
-}
-
-int VtableStub::pd_code_alignment() {
- // UltraSPARC cache line size is 8 instructions:
- const unsigned int icache_line_size = 32;
- return icache_line_size;
-}
diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
index 63d0759feb2..dbc66c7dbcf 100644
--- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
+++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
@@ -65,7 +65,7 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
#define INCLUDE_RTM_OPT 1
#endif
-#if defined(LINUX) || defined(SOLARIS) || defined(__APPLE__)
+#if defined(LINUX) || defined(__APPLE__)
#define SUPPORT_RESERVED_STACK_AREA
#endif
diff --git a/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp b/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp
index 7ba2625fcb3..9e3c6e209a4 100644
--- a/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp
+++ b/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright 2007, 2008, 2011 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -28,7 +28,7 @@
// Platform specific for C++ based Interpreter
-#if defined(PPC) || defined(SPARC) || defined(IA64)
+#if defined(PPC) || defined(IA64)
#define LOTS_OF_REGS // Use plenty of registers
#else
#undef LOTS_OF_REGS // Loser platforms
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index 1a9a45e77e0..148512a7bd4 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -222,12 +222,6 @@ static char cpu_arch[] = "amd64";
static char cpu_arch[] = "arm";
#elif defined(PPC32)
static char cpu_arch[] = "ppc";
-#elif defined(SPARC)
- #ifdef _LP64
-static char cpu_arch[] = "sparcv9";
- #else
-static char cpu_arch[] = "sparc";
- #endif
#else
#error Add appropriate cpu_arch setting
#endif
@@ -1365,9 +1359,6 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
{EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
{EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"},
{EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"},
- {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
- {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
- {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
{EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
{EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
{EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
@@ -1385,10 +1376,6 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
static Elf32_Half running_arch_code=EM_X86_64;
#elif (defined IA64)
static Elf32_Half running_arch_code=EM_IA_64;
- #elif (defined __sparc) && (defined _LP64)
- static Elf32_Half running_arch_code=EM_SPARCV9;
- #elif (defined __sparc) && (!defined _LP64)
- static Elf32_Half running_arch_code=EM_SPARC;
#elif (defined __powerpc64__)
static Elf32_Half running_arch_code=EM_PPC64;
#elif (defined __powerpc__)
@@ -1409,7 +1396,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
static Elf32_Half running_arch_code=EM_68K;
#else
#error Method os::dll_load requires that one of following is defined:\
- IA32, AMD64, IA64, __sparc, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K
+ IA32, AMD64, IA64, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K
#endif
// Identify compatability class for VM's architecture and library's architecture
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index 3e42d30ec0d..a704ee18a8d 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -3795,8 +3795,7 @@ size_t os::Linux::find_default_large_page_size() {
IA32_ONLY(4 * M)
IA64_ONLY(256 * M)
PPC_ONLY(4 * M)
- S390_ONLY(1 * M)
- SPARC_ONLY(4 * M);
+ S390_ONLY(1 * M);
#endif // ZERO
FILE *fp = fopen("/proc/meminfo", "r");
diff --git a/src/hotspot/os/posix/include/jvm_md.h b/src/hotspot/os/posix/include/jvm_md.h
index 13d778fba8f..2c8ebe06d70 100644
--- a/src/hotspot/os/posix/include/jvm_md.h
+++ b/src/hotspot/os/posix/include/jvm_md.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -54,7 +54,7 @@
#endif
#define JNI_LIB_NAME(NAME) JNI_LIB_PREFIX NAME JNI_LIB_SUFFIX
-#if defined(AIX) || defined(SOLARIS)
+#if defined(AIX)
#define JVM_MAXPATHLEN MAXPATHLEN
#else
// Hack: MAXPATHLEN is 4095 on some Linux and 4096 on others. This may
@@ -87,14 +87,8 @@
#define JVM_SIGTERM SIGTERM
#define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */
-#ifdef SOLARIS
-#define ASYNC_SIGNAL SIGJVM2 /* Event-based suspend/resume support */
-#endif // SOLARIS
#define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */
#define SHUTDOWN2_SIGNAL SIGINT
#define SHUTDOWN3_SIGNAL SIGTERM
-/* With 1.4.1 libjsig added versioning: used in os_solaris.cpp and jsig.c */
-#define JSIG_VERSION_1_4_1 0x30140100
-
#endif /* !_JAVASOFT_JVM_MD_H_ */
diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp
index 68b2d2dbfa7..2894cfc942e 100644
--- a/src/hotspot/os/posix/os_posix.cpp
+++ b/src/hotspot/os/posix/os_posix.cpp
@@ -458,7 +458,7 @@ void os::Posix::print_rlimit_info(outputStream* st) {
st->print("%d", sysconf(_SC_CHILD_MAX));
print_rlimit(st, ", THREADS", RLIMIT_THREADS);
-#elif !defined(SOLARIS)
+#else
print_rlimit(st, ", NPROC", RLIMIT_NPROC);
#endif
@@ -476,12 +476,6 @@ void os::Posix::print_rlimit_info(outputStream* st) {
print_rlimit(st, ", MEMLOCK", RLIMIT_MEMLOCK, true);
#endif
-#if defined(SOLARIS)
- // maximum size of mapped address space of a process in bytes;
- // if the limit is exceeded, mmap and brk fail
- print_rlimit(st, ", VMEM", RLIMIT_VMEM, true);
-#endif
-
// MacOS; The maximum size (in bytes) to which a process's resident set size may grow.
#if defined(__APPLE__)
print_rlimit(st, ", RSS", RLIMIT_RSS, true);
@@ -1105,21 +1099,6 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t
#if defined(IA64) && !defined(AIX)
{ SIGSEGV, SEGV_PSTKOVF, "SEGV_PSTKOVF", "Paragraph stack overflow" },
#endif
-#if defined(__sparc) && defined(SOLARIS)
-// define Solaris Sparc M7 ADI SEGV signals
-#if !defined(SEGV_ACCADI)
-#define SEGV_ACCADI 3
-#endif
- { SIGSEGV, SEGV_ACCADI, "SEGV_ACCADI", "ADI not enabled for mapped object." },
-#if !defined(SEGV_ACCDERR)
-#define SEGV_ACCDERR 4
-#endif
- { SIGSEGV, SEGV_ACCDERR, "SEGV_ACCDERR", "ADI disrupting exception." },
-#if !defined(SEGV_ACCPERR)
-#define SEGV_ACCPERR 5
-#endif
- { SIGSEGV, SEGV_ACCPERR, "SEGV_ACCPERR", "ADI precise exception." },
-#endif // defined(__sparc) && defined(SOLARIS)
{ SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." },
{ SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." },
{ SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." },
@@ -1278,13 +1257,7 @@ void os::print_siginfo(outputStream* os, const void* si0) {
bool os::signal_thread(Thread* thread, int sig, const char* reason) {
OSThread* osthread = thread->osthread();
if (osthread) {
-#if defined (SOLARIS)
- // Note: we cannot use pthread_kill on Solaris - not because
- // its missing, but because we do not have the pthread_t id.
- int status = thr_kill(osthread->thread_id(), sig);
-#else
int status = pthread_kill(osthread->pthread_id(), sig);
-#endif
if (status == 0) {
Events::log(Thread::current(), "sent signal %d to Thread " INTPTR_FORMAT " because %s.",
sig, p2i(thread), reason);
@@ -1305,8 +1278,6 @@ address os::Posix::ucontext_get_pc(const ucontext_t* ctx) {
return Bsd::ucontext_get_pc(ctx);
#elif defined(LINUX)
return Linux::ucontext_get_pc(ctx);
-#elif defined(SOLARIS)
- return Solaris::ucontext_get_pc(ctx);
#else
VMError::report_and_die("unimplemented ucontext_get_pc");
#endif
@@ -1319,8 +1290,6 @@ void os::Posix::ucontext_set_pc(ucontext_t* ctx, address pc) {
Bsd::ucontext_set_pc(ctx, pc);
#elif defined(LINUX)
Linux::ucontext_set_pc(ctx, pc);
-#elif defined(SOLARIS)
- Solaris::ucontext_set_pc(ctx, pc);
#else
VMError::report_and_die("unimplemented ucontext_get_pc");
#endif
@@ -1425,7 +1394,7 @@ bool os::same_files(const char* file1, const char* file2) {
// page size which again depends on the concrete system the VM is running
// on. Space for libc guard pages is not included in this size.
jint os::Posix::set_minimum_stack_sizes() {
- size_t os_min_stack_allowed = SOLARIS_ONLY(thr_min_stack()) NOT_SOLARIS(PTHREAD_STACK_MIN);
+ size_t os_min_stack_allowed = PTHREAD_STACK_MIN;
_java_thread_min_stack_allowed = _java_thread_min_stack_allowed +
JavaThread::stack_guard_zone_size() +
@@ -1635,11 +1604,9 @@ static void pthread_init_common(void) {
if ((status = pthread_mutexattr_settype(_mutexAttr, PTHREAD_MUTEX_NORMAL)) != 0) {
fatal("pthread_mutexattr_settype: %s", os::strerror(status));
}
- // Solaris has it's own PlatformMutex, distinct from the one for POSIX.
- NOT_SOLARIS(os::PlatformMutex::init();)
+ os::PlatformMutex::init();
}
-#ifndef SOLARIS
sigset_t sigs;
struct sigaction sigact[NSIG];
@@ -1655,7 +1622,6 @@ void os::Posix::save_preinstalled_handler(int sig, struct sigaction& oldAct) {
sigact[sig] = oldAct;
sigaddset(&sigs, sig);
}
-#endif
// Not all POSIX types and API's are available on all notionally "posix"
// platforms. If we have build-time support then we will check for actual
@@ -1740,7 +1706,6 @@ void os::Posix::init(void) {
pthread_init_common();
-#ifndef SOLARIS
int status;
if (_pthread_condattr_setclock != NULL && _clock_gettime != NULL) {
if ((status = _pthread_condattr_setclock(_condAttr, CLOCK_MONOTONIC)) != 0) {
@@ -1755,12 +1720,9 @@ void os::Posix::init(void) {
_use_clock_monotonic_condattr = true;
}
}
-#endif // !SOLARIS
-
}
void os::Posix::init_2(void) {
-#ifndef SOLARIS
log_info(os)("Use of CLOCK_MONOTONIC is%s supported",
(_clock_gettime != NULL ? "" : " not"));
log_info(os)("Use of pthread_condattr_setclock is%s supported",
@@ -1768,7 +1730,6 @@ void os::Posix::init_2(void) {
log_info(os)("Relative timed-wait using pthread_cond_timedwait is associated with %s",
_use_clock_monotonic_condattr ? "CLOCK_MONOTONIC" : "the default clock");
sigemptyset(&sigs);
-#endif // !SOLARIS
}
#else // !SUPPORTS_CLOCK_MONOTONIC
@@ -1778,12 +1739,10 @@ void os::Posix::init(void) {
}
void os::Posix::init_2(void) {
-#ifndef SOLARIS
log_info(os)("Use of CLOCK_MONOTONIC is not supported");
log_info(os)("Use of pthread_condattr_setclock is not supported");
log_info(os)("Relative timed-wait using pthread_cond_timedwait is associated with the default clock");
sigemptyset(&sigs);
-#endif // !SOLARIS
}
#endif // SUPPORTS_CLOCK_MONOTONIC
@@ -1924,7 +1883,6 @@ void os::Posix::to_RTC_abstime(timespec* abstime, int64_t millis) {
// Shared pthread_mutex/cond based PlatformEvent implementation.
// Not currently usable by Solaris.
-#ifndef SOLARIS
// PlatformEvent
//
@@ -2356,5 +2314,3 @@ int os::PlatformMonitor::wait(jlong millis) {
return OS_OK;
}
}
-
-#endif // !SOLARIS
diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp
index e036c98d27c..daa23db6274 100644
--- a/src/hotspot/os/posix/os_posix.hpp
+++ b/src/hotspot/os/posix/os_posix.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -172,8 +172,6 @@ private:
sigjmp_buf _jmpbuf;
};
-#ifndef SOLARIS
-
/*
* This is the platform-specific implementation underpinning
* the ParkEvent class, which itself underpins Java-level monitor
@@ -336,6 +334,4 @@ class PlatformMonitor : public PlatformMutex {
void notify_all();
};
-#endif // !SOLARIS
-
#endif // OS_POSIX_OS_POSIX_HPP
diff --git a/src/hotspot/os/posix/os_posix.inline.hpp b/src/hotspot/os/posix/os_posix.inline.hpp
index 9eb8d396416..852b8e1898e 100644
--- a/src/hotspot/os/posix/os_posix.inline.hpp
+++ b/src/hotspot/os/posix/os_posix.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,8 +45,6 @@ inline int os::Posix::clock_getres(clockid_t clock_id, struct timespec *tp) {
#endif // SUPPORTS_CLOCK_MONOTONIC
-#ifndef SOLARIS
-
// Platform Mutex/Monitor implementation
inline void os::PlatformMutex::lock() {
@@ -75,6 +73,4 @@ inline void os::PlatformMonitor::notify_all() {
assert_status(status == 0, status, "cond_broadcast");
}
-#endif // !SOLARIS
-
#endif // OS_POSIX_OS_POSIX_INLINE_HPP
diff --git a/src/hotspot/os/posix/vmError_posix.cpp b/src/hotspot/os/posix/vmError_posix.cpp
index 268cdb71a42..52f1e424e4d 100644
--- a/src/hotspot/os/posix/vmError_posix.cpp
+++ b/src/hotspot/os/posix/vmError_posix.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,9 +38,6 @@
#include
#include
#endif
-#ifdef SOLARIS
-#include
-#endif
#ifdef AIX
#include
#endif
diff --git a/src/hotspot/os/solaris/attachListener_solaris.cpp b/src/hotspot/os/solaris/attachListener_solaris.cpp
deleted file mode 100644
index 3b2f727437e..00000000000
--- a/src/hotspot/os/solaris/attachListener_solaris.cpp
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "logging/log.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/os.inline.hpp"
-#include "services/attachListener.hpp"
-#include "services/dtraceAttacher.hpp"
-#include "utilities/vmError.hpp"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-// stropts.h uses STR in stream ioctl defines
-#undef STR
-#include
-#undef STR
-#define STR(a) #a
-
-// The attach mechanism on Solaris is implemented using the Doors IPC
-// mechanism. The first tool to attempt to attach causes the attach
-// listener thread to startup. This thread creats a door that is
-// associated with a function that enqueues an operation to the attach
-// listener. The door is attached to a file in the file system so that
-// client (tools) can locate it. To enqueue an operation to the VM the
-// client calls through the door which invokes the enqueue function in
-// this process. The credentials of the client are checked and if the
-// effective uid matches this process then the operation is enqueued.
-// When an operation completes the attach listener is required to send the
-// operation result and any result data to the client. In this implementation
-// the result is returned via a UNIX domain socket. A pair of connected
-// sockets (socketpair) is created in the enqueue function and the file
-// descriptor for one of the sockets is returned to the client as the
-// return from the door call. The other end is retained in this process.
-// When the operation completes the result is sent to the client and
-// the socket is closed.
-
-// forward reference
-class SolarisAttachOperation;
-
-class SolarisAttachListener: AllStatic {
- private:
-
- // the path to which we attach the door file descriptor
- static char _door_path[PATH_MAX+1];
- static volatile bool _has_door_path;
-
- // door descriptor returned by door_create
- static int _door_descriptor;
-
- static bool _atexit_registered;
-
- // mutex to protect operation list
- static mutex_t _mutex;
-
- // semaphore to wakeup listener thread
- static sema_t _wakeup;
-
- static mutex_t* mutex() { return &_mutex; }
- static sema_t* wakeup() { return &_wakeup; }
-
- // enqueued operation list
- static SolarisAttachOperation* _head;
- static SolarisAttachOperation* _tail;
-
- static SolarisAttachOperation* head() { return _head; }
- static void set_head(SolarisAttachOperation* head) { _head = head; }
-
- static SolarisAttachOperation* tail() { return _tail; }
- static void set_tail(SolarisAttachOperation* tail) { _tail = tail; }
-
- // create the door
- static int create_door();
-
- public:
- enum {
- ATTACH_PROTOCOL_VER = 1 // protocol version
- };
- enum {
- ATTACH_ERROR_BADREQUEST = 100, // error code returned by
- ATTACH_ERROR_BADVERSION = 101, // the door call
- ATTACH_ERROR_RESOURCE = 102,
- ATTACH_ERROR_INTERNAL = 103,
- ATTACH_ERROR_DENIED = 104
- };
-
- static void set_door_path(char* path) {
- if (path == NULL) {
- _door_path[0] = '\0';
- _has_door_path = false;
- } else {
- strncpy(_door_path, path, PATH_MAX);
- _door_path[PATH_MAX] = '\0'; // ensure it's nul terminated
- _has_door_path = true;
- }
- }
-
- static void set_door_descriptor(int dd) { _door_descriptor = dd; }
-
- // initialize the listener
- static int init();
-
- static bool has_door_path() { return _has_door_path; }
- static char* door_path() { return _door_path; }
- static int door_descriptor() { return _door_descriptor; }
-
- // enqueue an operation
- static void enqueue(SolarisAttachOperation* op);
-
- // dequeue an operation
- static SolarisAttachOperation* dequeue();
-};
-
-
-// SolarisAttachOperation is an AttachOperation that additionally encapsulates
-// a socket connection to the requesting client/tool. SolarisAttachOperation
-// can additionally be held in a linked list.
-
-class SolarisAttachOperation: public AttachOperation {
- private:
- friend class SolarisAttachListener;
-
- // connection to client
- int _socket;
-
- // linked list support
- SolarisAttachOperation* _next;
-
- SolarisAttachOperation* next() { return _next; }
- void set_next(SolarisAttachOperation* next) { _next = next; }
-
- public:
- void complete(jint res, bufferedStream* st);
-
- int socket() const { return _socket; }
- void set_socket(int s) { _socket = s; }
-
- SolarisAttachOperation(char* name) : AttachOperation(name) {
- set_socket(-1);
- set_next(NULL);
- }
-};
-
-// statics
-char SolarisAttachListener::_door_path[PATH_MAX+1];
-volatile bool SolarisAttachListener::_has_door_path;
-int SolarisAttachListener::_door_descriptor = -1;
-bool SolarisAttachListener::_atexit_registered = false;
-mutex_t SolarisAttachListener::_mutex;
-sema_t SolarisAttachListener::_wakeup;
-SolarisAttachOperation* SolarisAttachListener::_head = NULL;
-SolarisAttachOperation* SolarisAttachListener::_tail = NULL;
-
-// Supporting class to help split a buffer into individual components
-class ArgumentIterator : public StackObj {
- private:
- char* _pos;
- char* _end;
- public:
- ArgumentIterator(char* arg_buffer, size_t arg_size) {
- _pos = arg_buffer;
- _end = _pos + arg_size - 1;
- }
- char* next() {
- if (*_pos == '\0') {
- // advance the iterator if possible (null arguments)
- if (_pos < _end) {
- _pos += 1;
- }
- return NULL;
- }
- char* res = _pos;
- char* next_pos = strchr(_pos, '\0');
- if (next_pos < _end) {
- next_pos++;
- }
- _pos = next_pos;
- return res;
- }
-};
-
-// Calls from the door function to check that the client credentials
-// match this process. Returns 0 if credentials okay, otherwise -1.
-static int check_credentials() {
- ucred_t *cred_info = NULL;
- int ret = -1; // deny by default
-
- // get client credentials
- if (door_ucred(&cred_info) == -1) {
- return -1; // unable to get them, deny
- }
-
- // get euid/egid from ucred_free
- uid_t ucred_euid = ucred_geteuid(cred_info);
- gid_t ucred_egid = ucred_getegid(cred_info);
-
- // check that the effective uid/gid matches
- if (os::Posix::matches_effective_uid_and_gid_or_root(ucred_euid, ucred_egid)) {
- ret = 0; // allow
- }
-
- ucred_free(cred_info);
- return ret;
-}
-
-
-// Parses the argument buffer to create an AttachOperation that we should
-// enqueue to the attach listener.
-// The buffer is expected to be formatted as follows:
-// 00000
-// where is the version number (must be "1"), is the command
-// name ("load, "datadump", ...) and is an argument.
-//
-static SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) {
- // assume bad request until parsed
- *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST;
-
- if (arg_size < 2 || argp[arg_size-1] != '\0') {
- return NULL; // no ver or not null terminated
- }
-
- // Use supporting class to iterate over the buffer
- ArgumentIterator args(argp, arg_size);
-
- // First check the protocol version
- char* ver = args.next();
- if (ver == NULL) {
- return NULL;
- }
- if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) {
- *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION;
- return NULL;
- }
-
- // Get command name and create the operation
- char* name = args.next();
- if (name == NULL || strlen(name) > AttachOperation::name_length_max) {
- return NULL;
- }
- SolarisAttachOperation* op = new SolarisAttachOperation(name);
-
- // Iterate over the arguments
- for (int i=0; iset_arg(i, NULL);
- } else {
- if (strlen(arg) > AttachOperation::arg_length_max) {
- delete op;
- return NULL;
- }
- op->set_arg(i, arg);
- }
- }
-
- // return operation
- *err = 0;
- return op;
-}
-
-// create special operation to indicate all clients have detached
-static SolarisAttachOperation* create_detachall_operation() {
- return new SolarisAttachOperation(AttachOperation::detachall_operation_name());
-}
-
-// This is door function which the client executes via a door_call.
-extern "C" {
- static void enqueue_proc(void* cookie, char* argp, size_t arg_size,
- door_desc_t* dt, uint_t n_desc)
- {
- int return_fd = -1;
- SolarisAttachOperation* op = NULL;
-
- // wait up to 10 seconds for listener to be up and running
- jint res = 0;
- int sleep_count = 0;
- while (!AttachListener::is_initialized()) {
- sleep(1); // 1 second
- sleep_count++;
- if (sleep_count > 10) { // try for 10 seconds
- debug_only(warning("door_call when not enabled"));
- res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL;
- break;
- }
- }
-
- // check client credentials
- if (res == 0) {
- if (check_credentials() != 0) {
- res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED;
- }
- }
-
- // if we are stopped at ShowMessageBoxOnError then maybe we can
- // load a diagnostic library
- if (res == 0 && VMError::is_error_reported()) {
- if (ShowMessageBoxOnError) {
- // TBD - support loading of diagnostic library here
- }
-
- // can't enqueue operation after fatal error
- res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
- }
-
- // create the operation
- if (res == 0) {
- int err;
- op = create_operation(argp, arg_size, &err);
- res = (op == NULL) ? (jint)err : 0;
- }
-
- // create a pair of connected sockets. Store the file descriptor
- // for one end in the operation and enqueue the operation. The
- // file descriptor for the other end wil be returned to the client.
- if (res == 0) {
- int s[2];
- if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) {
- delete op;
- res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
- } else {
- op->set_socket(s[0]);
- return_fd = s[1];
- SolarisAttachListener::enqueue(op);
- }
- }
-
- // Return 0 (success) + file descriptor, or non-0 (error)
- if (res == 0) {
- door_desc_t desc;
- // DOOR_RELEASE flag makes sure fd is closed after passing it to
- // the client. See door_return(3DOOR) man page.
- desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
- desc.d_data.d_desc.d_descriptor = return_fd;
- door_return((char*)&res, sizeof(res), &desc, 1);
- } else {
- door_return((char*)&res, sizeof(res), NULL, 0);
- }
- }
-}
-
-// atexit hook to detach the door and remove the file
-extern "C" {
- static void listener_cleanup() {
- int dd = SolarisAttachListener::door_descriptor();
- if (dd >= 0) {
- SolarisAttachListener::set_door_descriptor(-1);
- ::close(dd);
- }
- if (SolarisAttachListener::has_door_path()) {
- char* path = SolarisAttachListener::door_path();
- ::fdetach(path);
- ::unlink(path);
- SolarisAttachListener::set_door_path(NULL);
- }
- }
-}
-
-// Create the door
-int SolarisAttachListener::create_door() {
- char door_path[PATH_MAX+1];
- char initial_path[PATH_MAX+1];
- int fd, res;
-
- // register exit function
- if (!_atexit_registered) {
- _atexit_registered = true;
- ::atexit(listener_cleanup);
- }
-
- // create the door descriptor
- int dd = ::door_create(enqueue_proc, NULL, 0);
- if (dd < 0) {
- return -1;
- }
-
- // create initial file to attach door descriptor
- snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
- os::get_temp_directory(), os::current_process_id());
- snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path);
- RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd);
- if (fd == -1) {
- log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno);
- ::door_revoke(dd);
- return -1;
- }
- assert(fd >= 0, "bad file descriptor");
- ::close(fd);
-
- // attach the door descriptor to the file
- if ((res = ::fattach(dd, initial_path)) == -1) {
- // if busy then detach and try again
- if (errno == EBUSY) {
- ::fdetach(initial_path);
- res = ::fattach(dd, initial_path);
- }
- if (res == -1) {
- log_debug(attach)("unable to create door - fattach failed (%d)", errno);
- ::door_revoke(dd);
- dd = -1;
- }
- }
-
- // rename file so that clients can attach
- if (dd >= 0) {
- if (::rename(initial_path, door_path) == -1) {
- ::close(dd);
- ::fdetach(initial_path);
- log_debug(attach)("unable to create door - rename %s to %s failed (%d)", errno);
- dd = -1;
- }
- }
- if (dd >= 0) {
- set_door_descriptor(dd);
- set_door_path(door_path);
- log_trace(attach)("door file %s created succesfully", door_path);
- } else {
- // unable to create door, attach it to file, or rename file into place
- ::unlink(initial_path);
- return -1;
- }
-
- return 0;
-}
-
-// Initialization - create the door, locks, and other initialization
-int SolarisAttachListener::init() {
- if (create_door()) {
- return -1;
- }
-
- int status = os::Solaris::mutex_init(&_mutex);
- assert_status(status==0, status, "mutex_init");
-
- status = ::sema_init(&_wakeup, 0, NULL, NULL);
- assert_status(status==0, status, "sema_init");
-
- set_head(NULL);
- set_tail(NULL);
-
- return 0;
-}
-
-// Dequeue an operation
-SolarisAttachOperation* SolarisAttachListener::dequeue() {
- for (;;) {
- int res;
-
- // wait for somebody to enqueue something
- while ((res = ::sema_wait(wakeup())) == EINTR)
- ;
- if (res) {
- warning("sema_wait failed: %s", os::strerror(res));
- return NULL;
- }
-
- // lock the list
- res = os::Solaris::mutex_lock(mutex());
- assert(res == 0, "mutex_lock failed");
-
- // remove the head of the list
- SolarisAttachOperation* op = head();
- if (op != NULL) {
- set_head(op->next());
- if (head() == NULL) {
- set_tail(NULL);
- }
- }
-
- // unlock
- os::Solaris::mutex_unlock(mutex());
-
- // if we got an operation when return it.
- if (op != NULL) {
- return op;
- }
- }
-}
-
-// Enqueue an operation
-void SolarisAttachListener::enqueue(SolarisAttachOperation* op) {
- // lock list
- int res = os::Solaris::mutex_lock(mutex());
- assert(res == 0, "mutex_lock failed");
-
- // enqueue at tail
- op->set_next(NULL);
- if (head() == NULL) {
- set_head(op);
- } else {
- tail()->set_next(op);
- }
- set_tail(op);
-
- // wakeup the attach listener
- RESTARTABLE(::sema_post(wakeup()), res);
- assert(res == 0, "sema_post failed");
-
- // unlock
- os::Solaris::mutex_unlock(mutex());
-}
-
-
-// support function - writes the (entire) buffer to a socket
-static int write_fully(int s, char* buf, int len) {
- do {
- int n = ::write(s, buf, len);
- if (n == -1) {
- if (errno != EINTR) return -1;
- } else {
- buf += n;
- len -= n;
- }
- }
- while (len > 0);
- return 0;
-}
-
-// Complete an operation by sending the operation result and any result
-// output to the client. At this time the socket is in blocking mode so
-// potentially we can block if there is a lot of data and the client is
-// non-responsive. For most operations this is a non-issue because the
-// default send buffer is sufficient to buffer everything. In the future
-// if there are operations that involves a very big reply then it the
-// socket could be made non-blocking and a timeout could be used.
-
-void SolarisAttachOperation::complete(jint res, bufferedStream* st) {
- if (this->socket() >= 0) {
- JavaThread* thread = JavaThread::current();
- ThreadBlockInVM tbivm(thread);
-
- thread->set_suspend_equivalent();
- // cleared by handle_special_suspend_equivalent_condition() or
- // java_suspend_self() via check_and_wait_while_suspended()
-
- // write operation result
- char msg[32];
- sprintf(msg, "%d\n", res);
- int rc = write_fully(this->socket(), msg, strlen(msg));
-
- // write any result data
- if (rc == 0) {
- write_fully(this->socket(), (char*) st->base(), st->size());
- ::shutdown(this->socket(), 2);
- }
-
- // close socket and we're done
- ::close(this->socket());
-
- // were we externally suspended while we were waiting?
- thread->check_and_wait_while_suspended();
- }
- delete this;
-}
-
-
-// AttachListener functions
-
-AttachOperation* AttachListener::dequeue() {
- JavaThread* thread = JavaThread::current();
- ThreadBlockInVM tbivm(thread);
-
- thread->set_suspend_equivalent();
- // cleared by handle_special_suspend_equivalent_condition() or
- // java_suspend_self() via check_and_wait_while_suspended()
-
- AttachOperation* op = SolarisAttachListener::dequeue();
-
- // were we externally suspended while we were waiting?
- thread->check_and_wait_while_suspended();
-
- return op;
-}
-
-
-// Performs initialization at vm startup
-// For Solaris we remove any stale .java_pid file which could cause
-// an attaching process to think we are ready to receive a door_call
-// before we are properly initialized
-
-void AttachListener::vm_start() {
- char fn[PATH_MAX+1];
- struct stat64 st;
- int ret;
-
- int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d",
- os::get_temp_directory(), os::current_process_id());
- assert(n < sizeof(fn), "java_pid file name buffer overflow");
-
- RESTARTABLE(::stat64(fn, &st), ret);
- if (ret == 0) {
- ret = ::unlink(fn);
- if (ret == -1) {
- log_debug(attach)("Failed to remove stale attach pid file at %s", fn);
- }
- }
-}
-
-int AttachListener::pd_init() {
- JavaThread* thread = JavaThread::current();
- ThreadBlockInVM tbivm(thread);
-
- thread->set_suspend_equivalent();
- // cleared by handle_special_suspend_equivalent_condition() or
- // java_suspend_self()
-
- int ret_code = SolarisAttachListener::init();
-
- // were we externally suspended while we were waiting?
- thread->check_and_wait_while_suspended();
-
- return ret_code;
-}
-
-// Attach Listener is started lazily except in the case when
-// +ReduseSignalUsage is used
-bool AttachListener::init_at_startup() {
- if (ReduceSignalUsage) {
- return true;
- } else {
- return false;
- }
-}
-
-bool AttachListener::check_socket_file() {
- int ret;
- struct stat64 st;
- ret = stat64(SolarisAttachListener::door_path(), &st);
- if (ret == -1) { // need to restart attach listener.
- log_debug(attach)("Door file %s does not exist - Restart Attach Listener",
- SolarisAttachListener::door_path());
-
- listener_cleanup();
-
- // wait to terminate current attach listener instance...
- while (AttachListener::transit_state(AL_INITIALIZING,
- AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
- os::naked_yield();
- }
- return is_init_trigger();
- }
- return false;
-}
-
-// If the file .attach_pid exists in the working directory
-// or /tmp then this is the trigger to start the attach mechanism
-bool AttachListener::is_init_trigger() {
- if (init_at_startup() || is_initialized()) {
- return false; // initialized at startup or already initialized
- }
- char fn[PATH_MAX + 1];
- int ret;
- struct stat64 st;
- sprintf(fn, ".attach_pid%d", os::current_process_id());
- RESTARTABLE(::stat64(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);
- if (ret == -1) {
- log_debug(attach)("Failed to find attach file: %s", fn);
- }
- }
- if (ret == 0) {
- // simple check to avoid starting the attach mechanism when
- // a bogus non-root user creates the file
- if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
- init();
- log_trace(attach)("Attach triggered by %s", fn);
- return true;
- } else {
- log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
- }
- }
- return false;
-}
-
-// if VM aborts then detach/cleanup
-void AttachListener::abort() {
- listener_cleanup();
-}
-
-void AttachListener::pd_data_dump() {
- os::signal_notify(SIGQUIT);
-}
-
-static jint enable_dprobes(AttachOperation* op, outputStream* out) {
- const char* probe = op->arg(0);
- if (probe == NULL || probe[0] == '\0') {
- out->print_cr("No probe specified");
- return JNI_ERR;
- } else {
- char *end;
- long val = strtol(probe, &end, 10);
- if (end == probe || val < 0 || val > INT_MAX) {
- out->print_cr("invalid probe type");
- return JNI_ERR;
- } else {
- int probe_typess = (int) val;
- DTrace::enable_dprobes(probe_typess);
- return JNI_OK;
- }
- }
-}
-
-// platform specific operations table
-static AttachOperationFunctionInfo funcs[] = {
- { "enabledprobes", enable_dprobes },
- { NULL, NULL }
-};
-
-AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* name) {
- int i;
- for (i = 0; funcs[i].name != NULL; i++) {
- if (strcmp(funcs[i].name, name) == 0) {
- return &funcs[i];
- }
- }
- return NULL;
-}
-
-// Solaris specific global flag set. Currently, we support only
-// changing ExtendedDTraceProbes flag.
-jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) {
- const char* name = op->arg(0);
- assert(name != NULL, "flag name should not be null");
- bool flag = true;
- const char* arg1;
- if ((arg1 = op->arg(1)) != NULL) {
- char *end;
- flag = (strtol(arg1, &end, 10) != 0);
- if (arg1 == end) {
- out->print_cr("flag value has to be an integer");
- return JNI_ERR;
- }
- }
-
- if (strcmp(name, "ExtendedDTraceProbes") == 0) {
- DTrace::set_extended_dprobes(flag);
- return JNI_OK;
- }
-
- if (strcmp(name, "DTraceMonitorProbes") == 0) {
- DTrace::set_monitor_dprobes(flag);
- return JNI_OK;
- }
-
- out->print_cr("flag '%s' cannot be changed", name);
- return JNI_ERR;
-}
-
-void AttachListener::pd_detachall() {
- DTrace::detach_all_clients();
-}
diff --git a/src/hotspot/os/solaris/c1_globals_solaris.hpp b/src/hotspot/os/solaris/c1_globals_solaris.hpp
deleted file mode 100644
index 3c01a6cd2dc..00000000000
--- a/src/hotspot/os/solaris/c1_globals_solaris.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
-#define OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
-
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
-
-//
-// Sets the default values for operating system dependent flags used by the
-// client compiler. (see c1_globals.hpp)
-//
-
-#endif // OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
diff --git a/src/hotspot/os/solaris/c2_globals_solaris.hpp b/src/hotspot/os/solaris/c2_globals_solaris.hpp
deleted file mode 100644
index b4348b34df9..00000000000
--- a/src/hotspot/os/solaris/c2_globals_solaris.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
-#define OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
-
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
-
-//
-// Sets the default values for operating system dependent flags used by the
-// server compiler. (see c2_globals.hpp)
-//
-
-#endif // OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
diff --git a/src/hotspot/os/solaris/decoder_solaris.cpp b/src/hotspot/os/solaris/decoder_solaris.cpp
deleted file mode 100644
index 32b6e949531..00000000000
--- a/src/hotspot/os/solaris/decoder_solaris.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "utilities/decoder_elf.hpp"
-
-#include
-
-bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) {
- return !cplus_demangle(symbol, buf, (size_t)buflen);
-}
-
diff --git a/src/hotspot/os/solaris/dtrace/jhelper.d b/src/hotspot/os/solaris/dtrace/jhelper.d
deleted file mode 100644
index 87bdf4b07fc..00000000000
--- a/src/hotspot/os/solaris/dtrace/jhelper.d
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-/* This file is auto-generated */
-#include "JvmOffsetsIndex.h"
-
-#define DEBUG
-
-#ifdef DEBUG
-#define MARK_LINE this->line = __LINE__
-#else
-#define MARK_LINE
-#endif
-
-#ifdef _LP64
-#define STACK_BIAS 0x7ff
-#define pointer uint64_t
-#else
-#define STACK_BIAS 0
-#define pointer uint32_t
-#endif
-
-extern pointer __JvmOffsets;
-
-/* GrowableArray* */
-extern pointer __1cJCodeCacheG_heaps_;
-
-extern pointer __1cIUniverseO_collectedHeap_;
-
-extern pointer __1cHnmethodG__vtbl_;
-extern pointer __1cGMethodG__vtbl_;
-extern pointer __1cKBufferBlobG__vtbl_;
-
-#define copyin_ptr(ADDR) *(pointer*) copyin((pointer) (ADDR), sizeof(pointer))
-#define copyin_uchar(ADDR) *(uchar_t*) copyin((pointer) (ADDR), sizeof(uchar_t))
-#define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t))
-#define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t))
-#define copyin_int32(ADDR) *(int32_t*) copyin((pointer) (ADDR), sizeof(int32_t))
-#define copyin_uint8(ADDR) *(uint8_t*) copyin((pointer) (ADDR), sizeof(uint8_t))
-
-#define copyin_offset(JVM_CONST) JVM_CONST = \
- copyin_int32(JvmOffsetsPtr + IDX_##JVM_CONST * sizeof(int32_t))
-
-int init_done;
-
-dtrace:helper:ustack:
-{
- MARK_LINE;
- this->done = 0;
- /*
- * TBD:
- * Here we initialize init_done, otherwise jhelper does not work.
- * Therefore, copyin_offset() statements work multiple times now.
- * There is a hope we could avoid it in the future, and so,
- * this initialization can be removed.
- */
- init_done = 0;
- this->error = (char *) NULL;
- this->result = (char *) NULL;
- this->isMethod = 0;
- this->codecache = 0;
- this->klass = (pointer) NULL;
- this->vtbl = (pointer) NULL;
- this->suffix = '\0';
-}
-
-dtrace:helper:ustack:
-{
- MARK_LINE;
- /* Initialization of JvmOffsets constants */
- JvmOffsetsPtr = (pointer) &``__JvmOffsets;
-}
-
-dtrace:helper:ustack:
-/!init_done && !this->done/
-{
- MARK_LINE;
-
- copyin_offset(POINTER_SIZE);
- copyin_offset(COMPILER);
- copyin_offset(OFFSET_CollectedHeap_reserved);
- copyin_offset(OFFSET_MemRegion_start);
- copyin_offset(OFFSET_MemRegion_word_size);
- copyin_offset(SIZE_HeapWord);
-
- copyin_offset(OFFSET_interpreter_frame_method);
- copyin_offset(OFFSET_Klass_name);
- copyin_offset(OFFSET_ConstantPool_pool_holder);
-
- copyin_offset(OFFSET_HeapBlockHeader_used);
- copyin_offset(OFFSET_oopDesc_metadata);
-
- copyin_offset(OFFSET_Symbol_length);
- copyin_offset(OFFSET_Symbol_body);
-
- copyin_offset(OFFSET_Method_constMethod);
- copyin_offset(OFFSET_ConstMethod_constants);
- copyin_offset(OFFSET_ConstMethod_name_index);
- copyin_offset(OFFSET_ConstMethod_signature_index);
-
- copyin_offset(OFFSET_CodeHeap_memory);
- copyin_offset(OFFSET_CodeHeap_segmap);
- copyin_offset(OFFSET_CodeHeap_log2_segment_size);
-
- copyin_offset(OFFSET_GrowableArray_CodeHeap_data);
- copyin_offset(OFFSET_GrowableArray_CodeHeap_len);
-
- copyin_offset(OFFSET_VirtualSpace_low);
- copyin_offset(OFFSET_VirtualSpace_high);
-
- copyin_offset(OFFSET_CodeBlob_name);
-
- copyin_offset(OFFSET_nmethod_method);
- copyin_offset(SIZE_HeapBlockHeader);
- copyin_offset(SIZE_oopDesc);
- copyin_offset(SIZE_ConstantPool);
-
- copyin_offset(OFFSET_NarrowPtrStruct_base);
- copyin_offset(OFFSET_NarrowPtrStruct_shift);
-
- /*
- * The PC to translate is in arg0.
- */
- this->pc = arg0;
-
- /*
- * The methodPtr is in %l2 on SPARC. This can be found at
- * offset 8 from the frame pointer on 32-bit processes.
- */
-#if defined(__sparc)
- this->methodPtr = copyin_ptr(arg1 + 2 * sizeof(pointer) + STACK_BIAS);
-#elif defined(__i386) || defined(__amd64)
- this->methodPtr = copyin_ptr(arg1 + OFFSET_interpreter_frame_method);
-#else
-#error "Don't know architecture"
-#endif
-
- /* Read address of GrowableArray */
- // this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_);
- this->code_heaps_address = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cJCodeCacheG_heaps_ ) , sizeof ( uint64_t ) );
-
- /* Read address of _data array field in GrowableArray */
- this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data);
- this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len);
-
- this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_;
-
- /*
- * Get Java heap bounds
- */
- // this->Universe_collectedHeap = copyin_ptr(&``__1cIUniverseO_collectedHeap_);
- this->Universe_collectedHeap = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cIUniverseO_collectedHeap_ ) , sizeof ( uint64_t ) );
-
- this->heap_start = copyin_ptr(this->Universe_collectedHeap +
- OFFSET_CollectedHeap_reserved +
- OFFSET_MemRegion_start);
- this->heap_size = SIZE_HeapWord *
- copyin_ptr(this->Universe_collectedHeap +
- OFFSET_CollectedHeap_reserved +
- OFFSET_MemRegion_word_size
- );
- this->heap_end = this->heap_start + this->heap_size;
-}
-
-/*
- * IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in
- * the code cache. If more code heaps are added the following probes have to
- * be extended. This is done by simply adding a probe to get the heap bounds
- * and another probe to set the code heap address of the newly created heap.
- */
-
-/*
- * ----- BEGIN: Get bounds of code heaps -----
- */
-dtrace:helper:ustack:
-/init_done < 1 && this->number_of_heaps >= 1 && !this->done/
-{
- MARK_LINE;
- /* CodeHeap 1 */
- init_done = 1;
- this->code_heap1_address = copyin_ptr(this->code_heaps_array_address);
- this->code_heap1_low = copyin_ptr(this->code_heap1_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
- this->code_heap1_high = copyin_ptr(this->code_heap1_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
-}
-
-dtrace:helper:ustack:
-/init_done < 2 && this->number_of_heaps >= 2 && !this->done/
-{
- MARK_LINE;
- /* CodeHeap 2 */
- init_done = 2;
- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
- this->code_heap2_address = copyin_ptr(this->code_heaps_array_address);
- this->code_heap2_low = copyin_ptr(this->code_heap2_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
- this->code_heap2_high = copyin_ptr(this->code_heap2_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
-}
-
-dtrace:helper:ustack:
-/init_done < 3 && this->number_of_heaps >= 3 && !this->done/
-{
- /* CodeHeap 3 */
- init_done = 3;
- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
- this->code_heap3_address = copyin_ptr(this->code_heaps_array_address);
- this->code_heap3_low = copyin_ptr(this->code_heap3_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
- this->code_heap3_high = copyin_ptr(this->code_heap3_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
-}
-
-dtrace:helper:ustack:
-/init_done < 4 && this->number_of_heaps >= 4 && !this->done/
-{
- /* CodeHeap 4 */
- init_done = 4;
- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
- this->code_heap4_address = copyin_ptr(this->code_heaps_array_address);
- this->code_heap4_low = copyin_ptr(this->code_heap4_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
- this->code_heap4_high = copyin_ptr(this->code_heap4_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
-}
-
-dtrace:helper:ustack:
-/init_done < 5 && this->number_of_heaps >= 5 && !this->done/
-{
- /* CodeHeap 5 */
- init_done = 5;
- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
- this->code_heap5_address = copyin_ptr(this->code_heaps_array_address);
- this->code_heap5_low = copyin_ptr(this->code_heap5_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
- this->code_heap5_high = copyin_ptr(this->code_heap5_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
-}
-/*
- * ----- END: Get bounds of code heaps -----
- */
-
-/*
- * ----- BEGIN: Get address of the code heap pc points to -----
- */
-dtrace:helper:ustack:
-/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/
-{
- MARK_LINE;
- this->codecache = 1;
- this->code_heap_address = this->code_heap1_address;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/
-{
- MARK_LINE;
- this->codecache = 1;
- this->code_heap_address = this->code_heap2_address;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/
-{
- MARK_LINE;
- this->codecache = 1;
- this->code_heap_address = this->code_heap3_address;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/
-{
- MARK_LINE;
- this->codecache = 1;
- this->code_heap_address = this->code_heap4_address;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/
-{
- MARK_LINE;
- this->codecache = 1;
- this->code_heap_address = this->code_heap5_address;
-}
-/*
- * ----- END: Get address of the code heap pc points to -----
- */
-
-dtrace:helper:ustack:
-/!this->done && this->codecache/
-{
- MARK_LINE;
- /*
- * Get code heap configuration
- */
- this->code_heap_low = copyin_ptr(this->code_heap_address +
- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
- this->code_heap_segmap_low = copyin_ptr(this->code_heap_address +
- OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low);
- this->code_heap_log2_segment_size = copyin_uint32(
- this->code_heap_address + OFFSET_CodeHeap_log2_segment_size);
-
- /*
- * Find start
- */
- this->segment = (this->pc - this->code_heap_low) >>
- this->code_heap_log2_segment_size;
- this->block = this->code_heap_segmap_low;
- this->tag = copyin_uchar(this->block + this->segment);
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache && this->tag > 0/
-{
- MARK_LINE;
- this->tag = copyin_uchar(this->block + this->segment);
- this->segment = this->segment - this->tag;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache && this->tag > 0/
-{
- MARK_LINE;
- this->tag = copyin_uchar(this->block + this->segment);
- this->segment = this->segment - this->tag;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache && this->tag > 0/
-{
- MARK_LINE;
- this->tag = copyin_uchar(this->block + this->segment);
- this->segment = this->segment - this->tag;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache && this->tag > 0/
-{
- MARK_LINE;
- this->tag = copyin_uchar(this->block + this->segment);
- this->segment = this->segment - this->tag;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache && this->tag > 0/
-{
- MARK_LINE;
- this->tag = copyin_uchar(this->block + this->segment);
- this->segment = this->segment - this->tag;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache && this->tag > 0/
-{
- MARK_LINE;
- this->error = "";
- this->done = 1;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache/
-{
- MARK_LINE;
- this->block = this->code_heap_low +
- (this->segment << this->code_heap_log2_segment_size);
- this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used);
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache && !this->used/
-{
- MARK_LINE;
- this->error = "";
- this->done = 1;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache/
-{
- MARK_LINE;
- this->start = this->block + SIZE_HeapBlockHeader;
- this->vtbl = copyin_ptr(this->start);
-
- this->nmethod_vtbl = (pointer) &``__1cHnmethodG__vtbl_;
- this->BufferBlob_vtbl = (pointer) &``__1cKBufferBlobG__vtbl_;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->vtbl == this->nmethod_vtbl/
-{
- MARK_LINE;
- this->methodPtr = copyin_ptr(this->start + OFFSET_nmethod_method);
- this->suffix = '*';
- this->isMethod = 1;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->vtbl == this->BufferBlob_vtbl/
-{
- MARK_LINE;
- this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name);
-}
-
-
-dtrace:helper:ustack:
-/!this->done && this->vtbl == this->BufferBlob_vtbl && this->methodPtr != 0/
-{
- MARK_LINE;
- this->klass = copyin_ptr(this->methodPtr);
- this->isMethod = this->klass == this->Method_vtbl;
- this->done = !this->isMethod;
-}
-
-dtrace:helper:ustack:
-/!this->done && !this->isMethod/
-{
- MARK_LINE;
- this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name);
- this->result = this->name != 0 ? copyinstr(this->name) : "";
- this->done = 1;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->isMethod/
-{
- MARK_LINE;
- this->constMethod = copyin_ptr(this->methodPtr +
- OFFSET_Method_constMethod);
-
- this->nameIndex = copyin_uint16(this->constMethod +
- OFFSET_ConstMethod_name_index);
-
- this->signatureIndex = copyin_uint16(this->constMethod +
- OFFSET_ConstMethod_signature_index);
-
- this->constantPool = copyin_ptr(this->constMethod +
- OFFSET_ConstMethod_constants);
-
- this->nameSymbol = copyin_ptr(this->constantPool +
- this->nameIndex * sizeof (pointer) + SIZE_ConstantPool);
- /* The symbol is a CPSlot and has lower bit set to indicate metadata */
- this->nameSymbol &= (~1); /* remove metadata lsb */
-
- this->nameSymbolLength = copyin_uint16(this->nameSymbol +
- OFFSET_Symbol_length);
-
- this->signatureSymbol = copyin_ptr(this->constantPool +
- this->signatureIndex * sizeof (pointer) + SIZE_ConstantPool);
- this->signatureSymbol &= (~1); /* remove metadata lsb */
-
- this->signatureSymbolLength = copyin_uint16(this->signatureSymbol +
- OFFSET_Symbol_length);
-
- this->klassPtr = copyin_ptr(this->constantPool +
- OFFSET_ConstantPool_pool_holder);
-
- this->klassSymbol = copyin_ptr(this->klassPtr +
- OFFSET_Klass_name);
-
- this->klassSymbolLength = copyin_uint16(this->klassSymbol +
- OFFSET_Symbol_length);
-
- /*
- * Enough for three strings, plus the '.', plus the trailing '\0'.
- */
- this->result = (char *) alloca(this->klassSymbolLength +
- this->nameSymbolLength +
- this->signatureSymbolLength + 2 + 1);
-
- copyinto(this->klassSymbol + OFFSET_Symbol_body,
- this->klassSymbolLength, this->result);
-
- /*
- * Add the '.' between the class and the name.
- */
- this->result[this->klassSymbolLength] = '.';
-
- copyinto(this->nameSymbol + OFFSET_Symbol_body,
- this->nameSymbolLength,
- this->result + this->klassSymbolLength + 1);
-
- copyinto(this->signatureSymbol + OFFSET_Symbol_body,
- this->signatureSymbolLength,
- this->result + this->klassSymbolLength +
- this->nameSymbolLength + 1);
-
- /*
- * Now we need to add a trailing '\0' and possibly a tag character.
- */
- this->result[this->klassSymbolLength + 1 +
- this->nameSymbolLength +
- this->signatureSymbolLength] = this->suffix;
- this->result[this->klassSymbolLength + 2 +
- this->nameSymbolLength +
- this->signatureSymbolLength] = '\0';
-
- this->done = 1;
-}
-
-dtrace:helper:ustack:
-/this->done && this->error == (char *) NULL/
-{
- this->result;
-}
-
-dtrace:helper:ustack:
-/this->done && this->error != (char *) NULL/
-{
- this->error;
-}
-
-dtrace:helper:ustack:
-/!this->done && this->codecache/
-{
- this->done = 1;
- "error";
-}
-
-
-dtrace:helper:ustack:
-/!this->done/
-{
- NULL;
-}
diff --git a/src/hotspot/os/solaris/globals_solaris.hpp b/src/hotspot/os/solaris/globals_solaris.hpp
deleted file mode 100644
index 7e48f727f83..00000000000
--- a/src/hotspot/os/solaris/globals_solaris.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_GLOBALS_SOLARIS_HPP
-#define OS_SOLARIS_GLOBALS_SOLARIS_HPP
-
-//
-// Defines Solaris specific flags. They are not available on other platforms.
-//
-#define RUNTIME_OS_FLAGS(develop, \
- develop_pd, \
- product, \
- product_pd, \
- diagnostic, \
- diagnostic_pd, \
- notproduct, \
- range, \
- constraint) \
- \
- product(bool, UseExtendedFileIO, true, \
- "Enable workaround for limitations of stdio FILE structure")
-
-//
-// Defines Solaris-specific default values. The flags are available on all
-// platforms, but they may have different default values on other platforms.
-//
-define_pd_global(bool, UseLargePages, true);
-define_pd_global(bool, UseLargePagesIndividualAllocation, false);
-define_pd_global(bool, UseOSErrorReporting, false);
-define_pd_global(bool, UseThreadPriorities, false);
-
-#endif // OS_SOLARIS_GLOBALS_SOLARIS_HPP
diff --git a/src/hotspot/os/solaris/osThread_solaris.cpp b/src/hotspot/os/solaris/osThread_solaris.cpp
deleted file mode 100644
index d0e945c0246..00000000000
--- a/src/hotspot/os/solaris/osThread_solaris.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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.
- *
- */
-
-// no precompiled headers
-#include "runtime/handles.inline.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/os.hpp"
-#include "runtime/osThread.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/vmThread.hpp"
-
-#include
-
- // ***************************************************************
- // Platform dependent initialization and cleanup
- // ***************************************************************
-
-void OSThread::pd_initialize() {
- _thread_id = 0;
- sigemptyset(&_caller_sigmask);
-
- _vm_created_thread = false;
-}
-
-void OSThread::pd_destroy() {
-}
-
-// copied from synchronizer.cpp
-
-void OSThread::SR_handler(Thread* thread, ucontext_t* uc) {
- os::Solaris::SR_handler(thread, uc);
-}
diff --git a/src/hotspot/os/solaris/osThread_solaris.hpp b/src/hotspot/os/solaris/osThread_solaris.hpp
deleted file mode 100644
index d54ebae2dc5..00000000000
--- a/src/hotspot/os/solaris/osThread_solaris.hpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_OSTHREAD_SOLARIS_HPP
-#define OS_SOLARIS_OSTHREAD_SOLARIS_HPP
-
-// This is embedded via include into the class OSThread
- public:
- typedef thread_t thread_id_t;
-
- private:
- uint _lwp_id; // lwp ID, only used with bound threads
- int _native_priority; // Saved native priority when starting
- // a bound thread
- sigset_t _caller_sigmask; // Caller's signal mask
- bool _vm_created_thread; // true if the VM created this thread,
- // false if primary thread or attached thread
- public:
- uint lwp_id() const { return _lwp_id; }
- int native_priority() const { return _native_priority; }
-
- // Set and get state of _vm_created_thread flag
- void set_vm_created() { _vm_created_thread = true; }
- bool is_vm_created() { return _vm_created_thread; }
-
- // Methods to save/restore caller's signal mask
- sigset_t caller_sigmask() const { return _caller_sigmask; }
- void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; }
-
-#ifndef PRODUCT
- // Used for debugging, return a unique integer for each thread.
- int thread_identifier() const { return _thread_id; }
-#endif
-#ifdef ASSERT
- // On solaris reposition can fail in two ways:
- // 1: a mismatched pc, because signal is delivered too late, target thread
- // is resumed.
- // 2: on a timeout where signal is lost, target thread is resumed.
- bool valid_reposition_failure() {
- // only 1 and 2 can happen and we can handle both of them
- return true;
- }
-#endif
- void set_lwp_id(uint id) { _lwp_id = id; }
- void set_native_priority(int prio) { _native_priority = prio; }
-
- public:
- os::SuspendResume sr;
-
- private:
- ucontext_t* _ucontext;
-
- public:
- ucontext_t* ucontext() const { return _ucontext; }
- void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; }
- static void SR_handler(Thread* thread, ucontext_t* uc);
-
- // ***************************************************************
- // Platform dependent initialization and cleanup
- // ***************************************************************
-
-private:
-
- void pd_initialize();
- void pd_destroy();
-
-#endif // OS_SOLARIS_OSTHREAD_SOLARIS_HPP
diff --git a/src/hotspot/os/solaris/os_perf_solaris.cpp b/src/hotspot/os/solaris/os_perf_solaris.cpp
deleted file mode 100644
index bd33979a335..00000000000
--- a/src/hotspot/os/solaris/os_perf_solaris.cpp
+++ /dev/null
@@ -1,820 +0,0 @@
-/*
- * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "jvm.h"
-#include "memory/allocation.inline.hpp"
-#include "runtime/os.hpp"
-#include "runtime/os_perf.hpp"
-#include "os_solaris.inline.hpp"
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
-
-#include CPU_HEADER(vm_version_ext)
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-static const double NANOS_PER_SEC = 1000000000.0;
-
-struct CPUPerfTicks {
- kstat_t* kstat;
- uint64_t last_idle;
- uint64_t last_total;
- double last_ratio;
-};
-
-struct CPUPerfCounters {
- int nProcs;
- CPUPerfTicks* jvmTicks;
- kstat_ctl_t* kstat_ctrl;
-};
-
-static int get_info(const char* path, void* info, size_t s, off_t o) {
- assert(path != NULL, "path is NULL!");
- assert(info != NULL, "info is NULL!");
-
- int fd = -1;
-
- if ((fd = os::open(path, O_RDONLY, 0)) < 0) {
- return OS_ERR;
- }
- if (pread(fd, info, s, o) != s) {
- close(fd);
- return OS_ERR;
- }
- close(fd);
- return OS_OK;
-}
-
-static int get_psinfo2(void* info, size_t s, off_t o) {
- return get_info("/proc/self/psinfo", info, s, o);
-}
-
-static int get_psinfo(psinfo_t* info) {
- return get_psinfo2(info, sizeof(*info), 0);
-}
-
-static int get_psinfo(char* file, psinfo_t* info) {
- assert(file != NULL, "file is NULL!");
- assert(info != NULL, "info is NULL!");
- return get_info(file, info, sizeof(*info), 0);
-}
-
-
-static int get_usage(prusage_t* usage) {
- assert(usage != NULL, "usage is NULL!");
- return get_info("/proc/self/usage", usage, sizeof(*usage), 0);
-}
-
-static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) {
- assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!");
- assert(load != NULL, "load pointer is NULL!");
- assert(cpu_stat != NULL, "cpu_stat pointer is NULL!");
-
- if (load->kstat == NULL) {
- // no handle.
- return OS_ERR;
- }
- if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) {
- // disable handle for this CPU
- load->kstat = NULL;
- return OS_ERR;
- }
- return OS_OK;
-}
-
-static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) {
- assert(counters != NULL, "counters pointer is NULL!");
-
- cpu_stat_t cpu_stat = {0};
-
- if (which_logical_cpu >= counters->nProcs) {
- return .0;
- }
-
- CPUPerfTicks load = counters->jvmTicks[which_logical_cpu];
- if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) {
- return .0;
- }
-
- uint_t* usage = cpu_stat.cpu_sysinfo.cpu;
- if (usage == NULL) {
- return .0;
- }
-
- uint64_t c_idle = usage[CPU_IDLE];
- uint64_t c_total = 0;
-
- for (int i = 0; i < CPU_STATES; i++) {
- c_total += usage[i];
- }
-
- // Calculate diff against previous snapshot
- uint64_t d_idle = c_idle - load.last_idle;
- uint64_t d_total = c_total - load.last_total;
-
- /** update if weve moved */
- if (d_total > 0) {
- // Save current values for next time around
- load.last_idle = c_idle;
- load.last_total = c_total;
- load.last_ratio = (double) (d_total - d_idle) / d_total;
- }
-
- return load.last_ratio;
-}
-
-static int get_boot_time(uint64_t* time) {
- assert(time != NULL, "time pointer is NULL!");
- setutxent();
- for(;;) {
- struct utmpx* u;
- if ((u = getutxent()) == NULL) {
- break;
- }
- if (u->ut_type == BOOT_TIME) {
- *time = u->ut_xtime;
- endutxent();
- return OS_OK;
- }
- }
- endutxent();
- return OS_ERR;
-}
-
-static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) {
- assert(switches != NULL, "switches pointer is NULL!");
- assert(counters != NULL, "counter pointer is NULL!");
- *switches = 0;
- uint64_t s = 0;
-
- // Collect data from all CPUs
- for (int i = 0; i < counters->nProcs; i++) {
- cpu_stat_t cpu_stat = {0};
- CPUPerfTicks load = counters->jvmTicks[i];
-
- if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) {
- s += cpu_stat.cpu_sysinfo.pswitch;
- } else {
- //fail fast...
- return OS_ERR;
- }
- }
- *switches = s;
- return OS_OK;
-}
-
-static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) {
- assert(counters != NULL, "counters is NULL!");
- assert(rate != NULL, "rate pointer is NULL!");
- static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
- static uint64_t lastTime = 0;
- static uint64_t lastSwitches = 0;
- static double lastRate = 0.0;
-
- uint64_t lt = 0;
- int res = 0;
-
- if (lastTime == 0) {
- uint64_t tmp;
- if (get_boot_time(&tmp) < 0) {
- return OS_ERR;
- }
- lt = tmp * 1000;
- }
-
- res = OS_OK;
-
- pthread_mutex_lock(&contextSwitchLock);
- {
-
- uint64_t sw = 0;
- clock_t t, d;
-
- if (lastTime == 0) {
- lastTime = lt;
- }
-
- t = clock();
- d = t - lastTime;
-
- if (d == 0) {
- *rate = lastRate;
- } else if (get_noof_context_switches(counters, &sw)== OS_OK) {
- *rate = ((double)(sw - lastSwitches) / d) * 1000;
- lastRate = *rate;
- lastSwitches = sw;
- lastTime = t;
- } else {
- *rate = 0.0;
- res = OS_ERR;
- }
- if (*rate < 0.0) {
- *rate = 0.0;
- lastRate = 0.0;
- }
- }
- pthread_mutex_unlock(&contextSwitchLock);
- return res;
- }
-
-
-
-class CPUPerformanceInterface::CPUPerformance : public CHeapObj {
- friend class CPUPerformanceInterface;
- private:
- CPUPerfCounters _counters;
- int cpu_load(int which_logical_cpu, double* cpu_load);
- int context_switch_rate(double* rate);
- int cpu_load_total_process(double* cpu_load);
- int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
-
- CPUPerformance();
- ~CPUPerformance();
- bool initialize();
-};
-
-CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
- _counters.nProcs = 0;
- _counters.jvmTicks = NULL;
- _counters.kstat_ctrl = NULL;
-}
-
-bool CPUPerformanceInterface::CPUPerformance::initialize() {
- // initialize kstat control structure,
- _counters.kstat_ctrl = kstat_open();
- assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!");
-
- if (NULL == _counters.kstat_ctrl) {
- return false;
- }
-
- // Get number of CPU(s)
- if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) {
- // ignore error?
- _counters.nProcs = 1;
- }
-
- assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!");
- if (_counters.nProcs == 0) {
- return false;
- }
-
- // Data structure(s) for saving CPU load (one per CPU)
- size_t array_entry_count = _counters.nProcs;
- _counters.jvmTicks = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal);
- memset(_counters.jvmTicks, 0, array_entry_count * sizeof(*_counters.jvmTicks));
-
- // Get kstat cpu_stat counters for every CPU
- // loop over kstat to find our cpu_stat(s)
- int i = 0;
- for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
- if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
- if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) {
- continue;
- }
- if (i == _counters.nProcs) {
- // more cpu_stats than reported CPUs
- break;
- }
- _counters.jvmTicks[i++].kstat = kstat;
- }
- }
- return true;
-}
-
-CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
- FREE_C_HEAP_ARRAY(char, _counters.jvmTicks);
- if (_counters.kstat_ctrl != NULL) {
- kstat_close(_counters.kstat_ctrl);
- }
-}
-
-int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
- assert(cpu_load != NULL, "cpu_load pointer is NULL!");
- double t = .0;
- if (-1 == which_logical_cpu) {
- for (int i = 0; i < _counters.nProcs; i++) {
- t += get_cpu_load(i, &_counters);
- }
- // Cap total systemload to 1.0
- t = MIN2((t / _counters.nProcs), 1.0);
- } else {
- t = MIN2(get_cpu_load(which_logical_cpu, &_counters), 1.0);
- }
-
- *cpu_load = t;
- return OS_OK;
-}
-
-int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
- assert(cpu_load != NULL, "cpu_load pointer is NULL!");
-
- psinfo_t info;
-
- // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
- // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
- if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) {
- *cpu_load = 0.0;
- return OS_ERR;
- }
- *cpu_load = (double) info.pr_pctcpu / 0x8000;
- return OS_OK;
-}
-
-int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
- assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
- assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
- assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
-
- static uint64_t lastTime;
- static uint64_t lastUser, lastKernel;
- static double lastUserRes, lastKernelRes;
-
- pstatus_t pss;
- psinfo_t info;
-
- *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0;
- if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) {
- return OS_ERR;
- }
-
- if (get_psinfo(&info) != 0) {
- return OS_ERR;
- }
-
- // get the total time in user, kernel and total time
- // check ratios for 'lately' and multiply the 'recent load'.
- uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec;
- uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec;
- uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec;
- uint64_t diff = time - lastTime;
- double load = (double) info.pr_pctcpu / 0x8000;
-
- if (diff > 0) {
- lastUserRes = (load * (user - lastUser)) / diff;
- lastKernelRes = (load * (kernel - lastKernel)) / diff;
-
- // BUG9182835 - patch for clamping these values to sane ones.
- lastUserRes = MIN2(1, lastUserRes);
- lastUserRes = MAX2(0, lastUserRes);
- lastKernelRes = MIN2(1, lastKernelRes);
- lastKernelRes = MAX2(0, lastKernelRes);
- }
-
- double t = .0;
- cpu_load(-1, &t);
- // clamp at user+system and 1.0
- if (lastUserRes + lastKernelRes > t) {
- t = MIN2(lastUserRes + lastKernelRes, 1.0);
- }
-
- *pjvmUserLoad = lastUserRes;
- *pjvmKernelLoad = lastKernelRes;
- *psystemTotalLoad = t;
-
- lastTime = time;
- lastUser = user;
- lastKernel = kernel;
-
- return OS_OK;
-}
-
-int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
- return perf_context_switch_rate(&_counters, rate);
-}
-
-CPUPerformanceInterface::CPUPerformanceInterface() {
- _impl = NULL;
-}
-
-bool CPUPerformanceInterface::initialize() {
- _impl = new CPUPerformanceInterface::CPUPerformance();
- return _impl->initialize();
-}
-
-CPUPerformanceInterface::~CPUPerformanceInterface(void) {
- if (_impl != NULL) {
- delete _impl;
- }
-}
-
-int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
- return _impl->cpu_load(which_logical_cpu, cpu_load);
-}
-
-int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
- return _impl->cpu_load_total_process(cpu_load);
-}
-
-int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
- return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
-}
-
-int CPUPerformanceInterface::context_switch_rate(double* rate) const {
- return _impl->context_switch_rate(rate);
-}
-
-class SystemProcessInterface::SystemProcesses : public CHeapObj {
- friend class SystemProcessInterface;
- private:
- class ProcessIterator : public CHeapObj {
- friend class SystemProcessInterface::SystemProcesses;
- private:
- DIR* _dir;
- struct dirent* _entry;
- bool _valid;
-
- ProcessIterator();
- ~ProcessIterator();
- bool initialize();
-
- bool is_valid() const { return _valid; }
- bool is_valid_entry(struct dirent* const entry) const;
- bool is_dir(const char* const name) const;
- char* allocate_string(const char* const str) const;
- int current(SystemProcess* const process_info);
- int next_process();
- };
-
- ProcessIterator* _iterator;
- SystemProcesses();
- bool initialize();
- ~SystemProcesses();
-
- //information about system processes
- int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
-};
-
-bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
- struct stat64 mystat;
- int ret_val = 0;
-
- ret_val = ::stat64(name, &mystat);
-
- if (ret_val < 0) {
- return false;
- }
- ret_val = S_ISDIR(mystat.st_mode);
- return ret_val > 0;
-}
-
-// if it has a numeric name, is a directory and has a 'psinfo' file in it
-bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
- // ignore the "." and ".." directories
- if ((strcmp(entry->d_name, ".") == 0) ||
- (strcmp(entry->d_name, "..") == 0)) {
- return false;
- }
-
- char buffer[PATH_MAX] = {0};
- uint64_t size = 0;
- bool result = false;
- FILE *fp = NULL;
-
- if (atoi(entry->d_name) != 0) {
- jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
-
- if (is_dir(buffer)) {
- memset(buffer, 0, PATH_MAX);
- jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name);
- if ((fp = fopen(buffer, "r")) != NULL) {
- int nread = 0;
- psinfo_t psinfo_data;
- if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) {
- // only considering system process owned by root
- if (psinfo_data.pr_uid == 0) {
- result = true;
- }
- }
- }
- }
- }
-
- if (fp != NULL) {
- fclose(fp);
- }
-
- return result;
-}
-
-char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
- if (str != NULL) {
- return os::strdup_check_oom(str, mtInternal);
- }
- return NULL;
-}
-
-int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
- if (!is_valid()) {
- return OS_ERR;
- }
-
- char psinfo_path[PATH_MAX] = {0};
- jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name);
-
- FILE *fp = NULL;
- if ((fp = fopen(psinfo_path, "r")) == NULL) {
- return OS_ERR;
- }
-
- int nread = 0;
- psinfo_t psinfo_data;
- if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) {
- fclose(fp);
- return OS_ERR;
- }
-
- char *exe_path = NULL;
- if ((psinfo_data.pr_fname != NULL) &&
- (psinfo_data.pr_psargs != NULL)) {
- char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname);
- if (path_substring != NULL) {
- int len = path_substring - psinfo_data.pr_psargs;
- exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
- jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs);
- exe_path[len] = '\0';
- }
- }
-
- process_info->set_pid(atoi(_entry->d_name));
- process_info->set_name(allocate_string(psinfo_data.pr_fname));
- process_info->set_path(allocate_string(exe_path));
- process_info->set_command_line(allocate_string(psinfo_data.pr_psargs));
-
- if (exe_path != NULL) {
- FREE_C_HEAP_ARRAY(char, exe_path);
- }
-
- if (fp != NULL) {
- fclose(fp);
- }
-
- return OS_OK;
-}
-
-int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
- if (!is_valid()) {
- return OS_ERR;
- }
-
- do {
- _entry = os::readdir(_dir);
- if (_entry == NULL) {
- // Error or reached end. Could use errno to distinguish those cases.
- _valid = false;
- return OS_ERR;
- }
- } while(!is_valid_entry(_entry));
-
- _valid = true;
- return OS_OK;
-}
-
-SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
- _dir = NULL;
- _entry = NULL;
- _valid = false;
-}
-
-bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
- _dir = os::opendir("/proc");
- _entry = NULL;
- _valid = true;
- next_process();
-
- return true;
-}
-
-SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
- if (_dir != NULL) {
- os::closedir(_dir);
- }
-}
-
-SystemProcessInterface::SystemProcesses::SystemProcesses() {
- _iterator = NULL;
-}
-
-bool SystemProcessInterface::SystemProcesses::initialize() {
- _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
- return _iterator->initialize();
-}
-
-SystemProcessInterface::SystemProcesses::~SystemProcesses() {
- if (_iterator != NULL) {
- delete _iterator;
- }
-}
-
-int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
- assert(system_processes != NULL, "system_processes pointer is NULL!");
- assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
- assert(_iterator != NULL, "iterator is NULL!");
-
- // initialize pointers
- *no_of_sys_processes = 0;
- *system_processes = NULL;
-
- while (_iterator->is_valid()) {
- SystemProcess* tmp = new SystemProcess();
- _iterator->current(tmp);
-
- //if already existing head
- if (*system_processes != NULL) {
- //move "first to second"
- tmp->set_next(*system_processes);
- }
- // new head
- *system_processes = tmp;
- // increment
- (*no_of_sys_processes)++;
- // step forward
- _iterator->next_process();
- }
- return OS_OK;
-}
-
-int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
- return _impl->system_processes(system_procs, no_of_sys_processes);
-}
-
-SystemProcessInterface::SystemProcessInterface() {
- _impl = NULL;
-}
-
-bool SystemProcessInterface::initialize() {
- _impl = new SystemProcessInterface::SystemProcesses();
- return _impl->initialize();
-
-}
-
-SystemProcessInterface::~SystemProcessInterface() {
- if (_impl != NULL) {
- delete _impl;
- }
-}
-
-CPUInformationInterface::CPUInformationInterface() {
- _cpu_info = NULL;
-}
-
-bool CPUInformationInterface::initialize() {
- _cpu_info = new CPUInformation();
- _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
- _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
- _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
- _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
- _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
- return true;
-}
-
-CPUInformationInterface::~CPUInformationInterface() {
- if (_cpu_info != NULL) {
- if (_cpu_info->cpu_name() != NULL) {
- const char* cpu_name = _cpu_info->cpu_name();
- FREE_C_HEAP_ARRAY(char, cpu_name);
- _cpu_info->set_cpu_name(NULL);
- }
- if (_cpu_info->cpu_description() != NULL) {
- const char* cpu_desc = _cpu_info->cpu_description();
- FREE_C_HEAP_ARRAY(char, cpu_desc);
- _cpu_info->set_cpu_description(NULL);
- }
- delete _cpu_info;
- }
-}
-
-int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
- if (_cpu_info == NULL) {
- return OS_ERR;
- }
-
- cpu_info = *_cpu_info; // shallow copy assignment
- return OS_OK;
-}
-
-class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj {
- friend class NetworkPerformanceInterface;
- private:
- NetworkPerformance();
- NONCOPYABLE(NetworkPerformance);
- bool initialize();
- ~NetworkPerformance();
- int network_utilization(NetworkInterface** network_interfaces) const;
-};
-
-NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
-
-}
-
-bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
- return true;
-}
-
-NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
-
-}
-
-int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
-{
- kstat_ctl_t* ctl = kstat_open();
- if (ctl == NULL) {
- return OS_ERR;
- }
-
- NetworkInterface* ret = NULL;
- for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) {
- if (strcmp(k->ks_class, "net") != 0) {
- continue;
- }
- if (strcmp(k->ks_module, "link") != 0) {
- continue;
- }
-
- if (kstat_read(ctl, k, NULL) == -1) {
- return OS_ERR;
- }
-
- uint64_t bytes_in = UINT64_MAX;
- uint64_t bytes_out = UINT64_MAX;
- for (int i = 0; i < k->ks_ndata; ++i) {
- kstat_named_t* data = &reinterpret_cast(k->ks_data)[i];
- if (strcmp(data->name, "rbytes64") == 0) {
- bytes_in = data->value.ui64;
- }
- else if (strcmp(data->name, "obytes64") == 0) {
- bytes_out = data->value.ui64;
- }
- }
-
- if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) {
- NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret);
- ret = cur;
- }
- }
-
- kstat_close(ctl);
- *network_interfaces = ret;
-
- return OS_OK;
-}
-
-NetworkPerformanceInterface::NetworkPerformanceInterface() {
- _impl = NULL;
-}
-
-NetworkPerformanceInterface::~NetworkPerformanceInterface() {
- if (_impl != NULL) {
- delete _impl;
- }
-}
-
-bool NetworkPerformanceInterface::initialize() {
- _impl = new NetworkPerformanceInterface::NetworkPerformance();
- return _impl->initialize();
-}
-
-int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
- return _impl->network_utilization(network_interfaces);
-}
diff --git a/src/hotspot/os/solaris/os_share_solaris.hpp b/src/hotspot/os/solaris/os_share_solaris.hpp
deleted file mode 100644
index aa7f613b0d3..00000000000
--- a/src/hotspot/os/solaris/os_share_solaris.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_OS_SHARE_SOLARIS_HPP
-#define OS_SOLARIS_OS_SHARE_SOLARIS_HPP
-
-// Defines the interfaces to Solaris operating systems that vary across platforms
-
-// misc
-extern "C" {
- void signalHandler(int, siginfo_t*, void*);
-}
-void resolve_lwp_exit_calls(void);
-void handle_unexpected_exception(Thread* thread, int sig, siginfo_t* info, address pc, address adjusted_pc);
-#ifndef PRODUCT
-void continue_with_dump(void);
-#endif
-
-#define PROCFILE_LENGTH 128
-
-#endif // OS_SOLARIS_OS_SHARE_SOLARIS_HPP
diff --git a/src/hotspot/os/solaris/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp
deleted file mode 100644
index ee268a683c2..00000000000
--- a/src/hotspot/os/solaris/os_solaris.cpp
+++ /dev/null
@@ -1,5226 +0,0 @@
-/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-// no precompiled headers
-#include "jvm.h"
-#include "classfile/classLoader.hpp"
-#include "classfile/systemDictionary.hpp"
-#include "classfile/vmSymbols.hpp"
-#include "code/icBuffer.hpp"
-#include "code/vtableStubs.hpp"
-#include "compiler/compileBroker.hpp"
-#include "compiler/disassembler.hpp"
-#include "interpreter/interpreter.hpp"
-#include "logging/log.hpp"
-#include "logging/logStream.hpp"
-#include "memory/allocation.inline.hpp"
-#include "memory/filemap.hpp"
-#include "memory/universe.hpp"
-#include "oops/oop.inline.hpp"
-#include "os_share_solaris.hpp"
-#include "os_solaris.inline.hpp"
-#include "prims/jniFastGetField.hpp"
-#include "prims/jvm_misc.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/atomic.hpp"
-#include "runtime/extendedPC.hpp"
-#include "runtime/globals.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/java.hpp"
-#include "runtime/javaCalls.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/objectMonitor.hpp"
-#include "runtime/orderAccess.hpp"
-#include "runtime/osThread.hpp"
-#include "runtime/perfMemory.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/statSampler.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/threadCritical.hpp"
-#include "runtime/timer.hpp"
-#include "runtime/vm_version.hpp"
-#include "semaphore_posix.hpp"
-#include "services/attachListener.hpp"
-#include "services/memTracker.hpp"
-#include "services/runtimeService.hpp"
-#include "utilities/align.hpp"
-#include "utilities/decoder.hpp"
-#include "utilities/defaultStream.hpp"
-#include "utilities/events.hpp"
-#include "utilities/growableArray.hpp"
-#include "utilities/macros.hpp"
-#include "utilities/vmError.hpp"
-
-// put OS-includes here
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include // for elf Sym structure used by dladdr1
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-
-# define _STRUCTURED_PROC 1 // this gets us the new structured proc interfaces of 5.6 & later
-# include // see comment in
-
-#define MAX_PATH (2 * K)
-
-// for timer info max values which include all bits
-#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
-
-
-// Here are some liblgrp types from sys/lgrp_user.h to be able to
-// compile on older systems without this header file.
-
-#ifndef MADV_ACCESS_LWP
- #define MADV_ACCESS_LWP 7 /* next LWP to access heavily */
-#endif
-#ifndef MADV_ACCESS_MANY
- #define MADV_ACCESS_MANY 8 /* many processes to access heavily */
-#endif
-
-#ifndef LGRP_RSRC_CPU
- #define LGRP_RSRC_CPU 0 /* CPU resources */
-#endif
-#ifndef LGRP_RSRC_MEM
- #define LGRP_RSRC_MEM 1 /* memory resources */
-#endif
-
-// Values for ThreadPriorityPolicy == 1
-int prio_policy1[CriticalPriority+1] = {
- -99999, 0, 16, 32, 48, 64,
- 80, 96, 112, 124, 127, 127 };
-
-// System parameters used internally
-static clock_t clock_tics_per_sec = 100;
-
-// Track if we have called enable_extended_FILE_stdio (on Solaris 10u4+)
-static bool enabled_extended_FILE_stdio = false;
-
-// For diagnostics to print a message once. see run_periodic_checks
-static bool check_addr0_done = false;
-static sigset_t check_signal_done;
-static bool check_signals = true;
-
-address os::Solaris::handler_start; // start pc of thr_sighndlrinfo
-address os::Solaris::handler_end; // end pc of thr_sighndlrinfo
-
-address os::Solaris::_main_stack_base = NULL; // 4352906 workaround
-
-os::Solaris::pthread_setname_np_func_t os::Solaris::_pthread_setname_np = NULL;
-
-// "default" initializers for missing libc APIs
-extern "C" {
- static int lwp_mutex_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; }
- static int lwp_mutex_destroy(mutex_t *mx) { return 0; }
-
- static int lwp_cond_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; }
- static int lwp_cond_destroy(cond_t *cv) { return 0; }
-}
-
-// "default" initializers for pthread-based synchronization
-extern "C" {
- static int pthread_mutex_default_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; }
- static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; }
-}
-
-static void unpackTime(timespec* absTime, bool isAbsolute, jlong time);
-
-static inline size_t adjust_stack_size(address base, size_t size) {
- if ((ssize_t)size < 0) {
- // 4759953: Compensate for ridiculous stack size.
- size = max_intx;
- }
- if (size > (size_t)base) {
- // 4812466: Make sure size doesn't allow the stack to wrap the address space.
- size = (size_t)base;
- }
- return size;
-}
-
-static inline stack_t get_stack_info() {
- stack_t st;
- int retval = thr_stksegment(&st);
- st.ss_size = adjust_stack_size((address)st.ss_sp, st.ss_size);
- assert(retval == 0, "incorrect return value from thr_stksegment");
- assert((address)&st < (address)st.ss_sp, "Invalid stack base returned");
- assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned");
- return st;
-}
-
-static void _handle_uncaught_cxx_exception() {
- VMError::report_and_die("An uncaught C++ exception");
-}
-
-bool os::is_primordial_thread(void) {
- int r = thr_main();
- guarantee(r == 0 || r == 1, "CR6501650 or CR6493689");
- return r == 1;
-}
-
-address os::current_stack_base() {
- bool _is_primordial_thread = is_primordial_thread();
-
- // Workaround 4352906, avoid calls to thr_stksegment by
- // thr_main after the first one (it looks like we trash
- // some data, causing the value for ss_sp to be incorrect).
- if (!_is_primordial_thread || os::Solaris::_main_stack_base == NULL) {
- stack_t st = get_stack_info();
- if (_is_primordial_thread) {
- // cache initial value of stack base
- os::Solaris::_main_stack_base = (address)st.ss_sp;
- }
- return (address)st.ss_sp;
- } else {
- guarantee(os::Solaris::_main_stack_base != NULL, "Attempt to use null cached stack base");
- return os::Solaris::_main_stack_base;
- }
-}
-
-size_t os::current_stack_size() {
- size_t size;
-
- if (!is_primordial_thread()) {
- size = get_stack_info().ss_size;
- } else {
- struct rlimit limits;
- getrlimit(RLIMIT_STACK, &limits);
- size = adjust_stack_size(os::Solaris::_main_stack_base, (size_t)limits.rlim_cur);
- }
- // base may not be page aligned
- address base = current_stack_base();
- address bottom = align_up(base - size, os::vm_page_size());;
- return (size_t)(base - bottom);
-}
-
-struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
- return localtime_r(clock, res);
-}
-
-void os::Solaris::try_enable_extended_io() {
- typedef int (*enable_extended_FILE_stdio_t)(int, int);
-
- if (!UseExtendedFileIO) {
- return;
- }
-
- enable_extended_FILE_stdio_t enabler =
- (enable_extended_FILE_stdio_t) dlsym(RTLD_DEFAULT,
- "enable_extended_FILE_stdio");
- if (enabler) {
- enabler(-1, -1);
- }
-}
-
-jint os::Solaris::_os_thread_limit = 0;
-volatile jint os::Solaris::_os_thread_count = 0;
-
-julong os::available_memory() {
- return Solaris::available_memory();
-}
-
-julong os::Solaris::available_memory() {
- return (julong)sysconf(_SC_AVPHYS_PAGES) * os::vm_page_size();
-}
-
-julong os::Solaris::_physical_memory = 0;
-
-julong os::physical_memory() {
- return Solaris::physical_memory();
-}
-
-static hrtime_t first_hrtime = 0;
-static const hrtime_t hrtime_hz = 1000*1000*1000;
-static volatile hrtime_t max_hrtime = 0;
-
-
-void os::Solaris::initialize_system_info() {
- set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
- _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) *
- (julong)sysconf(_SC_PAGESIZE);
-}
-
-uint os::processor_id() {
- const processorid_t id = ::getcpuid();
- assert(id >= 0 && id < _processor_count, "Invalid processor id");
- return (uint)id;
-}
-
-int os::active_processor_count() {
- // User has overridden the number of active processors
- if (ActiveProcessorCount > 0) {
- log_trace(os)("active_processor_count: "
- "active processor count set by user : %d",
- ActiveProcessorCount);
- return ActiveProcessorCount;
- }
-
- int online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
- pid_t pid = getpid();
- psetid_t pset = PS_NONE;
- // Are we running in a processor set or is there any processor set around?
- if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) {
- uint_t pset_cpus;
- // Query the number of cpus available to us.
- if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) {
- assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check");
- return pset_cpus;
- }
- }
- // Otherwise return number of online cpus
- return online_cpus;
-}
-
-void os::set_native_thread_name(const char *name) {
- if (Solaris::_pthread_setname_np != NULL) {
- // Only the first 31 bytes of 'name' are processed by pthread_setname_np
- // but we explicitly copy into a size-limited buffer to avoid any
- // possible overflow.
- char buf[32];
- snprintf(buf, sizeof(buf), "%s", name);
- buf[sizeof(buf) - 1] = '\0';
- Solaris::_pthread_setname_np(pthread_self(), buf);
- }
-}
-
-bool os::bind_to_processor(uint processor_id) {
- // We assume that a processorid_t can be stored in a uint.
- assert(sizeof(uint) == sizeof(processorid_t),
- "can't convert uint to processorid_t");
- int bind_result =
- processor_bind(P_LWPID, // bind LWP.
- P_MYID, // bind current LWP.
- (processorid_t) processor_id, // id.
- NULL); // don't return old binding.
- return (bind_result == 0);
-}
-
-// Return true if user is running as root.
-
-bool os::have_special_privileges() {
- static bool init = false;
- static bool privileges = false;
- if (!init) {
- privileges = (getuid() != geteuid()) || (getgid() != getegid());
- init = true;
- }
- return privileges;
-}
-
-
-void os::init_system_properties_values() {
- // The next steps are taken in the product version:
- //
- // Obtain the JAVA_HOME value from the location of libjvm.so.
- // This library should be located at:
- // /jre/lib//{client|server}/libjvm.so.
- //
- // If "/jre/lib/" appears at the right place in the path, then we
- // assume libjvm.so is installed in a JDK and we use this path.
- //
- // Otherwise exit with message: "Could not create the Java virtual machine."
- //
- // The following extra steps are taken in the debugging version:
- //
- // If "/jre/lib/" does NOT appear at the right place in the path
- // instead of exit check for $JAVA_HOME environment variable.
- //
- // If it is defined and we are able to locate $JAVA_HOME/jre/lib/,
- // then we append a fake suffix "hotspot/libjvm.so" to this path so
- // it looks like libjvm.so is installed there
- // /jre/lib//hotspot/libjvm.so.
- //
- // Otherwise exit.
- //
- // Important note: if the location of libjvm.so changes this
- // code needs to be changed accordingly.
-
-// Base path of extensions installed on the system.
-#define SYS_EXT_DIR "/usr/jdk/packages"
-#define EXTENSIONS_DIR "/lib/ext"
-
- // Buffer that fits several sprintfs.
- // Note that the space for the colon and the trailing null are provided
- // by the nulls included by the sizeof operator.
- const size_t bufsize =
- MAX3((size_t)MAXPATHLEN, // For dll_dir & friends.
- sizeof(SYS_EXT_DIR) + sizeof("/lib/"), // invariant ld_library_path
- (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir
- char *buf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
-
- // sysclasspath, java_home, dll_dir
- {
- char *pslash;
- os::jvm_path(buf, bufsize);
-
- // Found the full path to libjvm.so.
- // Now cut the path to /jre if we can.
- *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
- pslash = strrchr(buf, '/');
- if (pslash != NULL) {
- *pslash = '\0'; // Get rid of /{client|server|hotspot}.
- }
- Arguments::set_dll_dir(buf);
-
- if (pslash != NULL) {
- pslash = strrchr(buf, '/');
- if (pslash != NULL) {
- *pslash = '\0'; // Get rid of /lib.
- }
- }
- Arguments::set_java_home(buf);
- if (!set_boot_path('/', ':')) {
- vm_exit_during_initialization("Failed setting boot class path.", NULL);
- }
- }
-
- // Where to look for native libraries.
- {
- // Use dlinfo() to determine the correct java.library.path.
- //
- // If we're launched by the Java launcher, and the user
- // does not set java.library.path explicitly on the commandline,
- // the Java launcher sets LD_LIBRARY_PATH for us and unsets
- // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case
- // dlinfo returns LD_LIBRARY_PATH + crle settings (including
- // /usr/lib), which is exactly what we want.
- //
- // If the user does set java.library.path, it completely
- // overwrites this setting, and always has.
- //
- // If we're not launched by the Java launcher, we may
- // get here with any/all of the LD_LIBRARY_PATH[_32|64]
- // settings. Again, dlinfo does exactly what we want.
-
- Dl_serinfo info_sz, *info = &info_sz;
- Dl_serpath *path;
- char *library_path;
- char *common_path = buf;
-
- // Determine search path count and required buffer size.
- if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) {
- FREE_C_HEAP_ARRAY(char, buf);
- vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror());
- }
-
- // Allocate new buffer and initialize.
- info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal);
- info->dls_size = info_sz.dls_size;
- info->dls_cnt = info_sz.dls_cnt;
-
- // Obtain search path information.
- if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) {
- FREE_C_HEAP_ARRAY(char, buf);
- FREE_C_HEAP_ARRAY(char, info);
- vm_exit_during_initialization("dlinfo SERINFO request", dlerror());
- }
-
- path = &info->dls_serpath[0];
-
- // Note: Due to a legacy implementation, most of the library path
- // is set in the launcher. This was to accomodate linking restrictions
- // on legacy Solaris implementations (which are no longer supported).
- // Eventually, all the library path setting will be done here.
- //
- // However, to prevent the proliferation of improperly built native
- // libraries, the new path component /usr/jdk/packages is added here.
-
- // Construct the invariant part of ld_library_path.
- sprintf(common_path, SYS_EXT_DIR "/lib");
-
- // Struct size is more than sufficient for the path components obtained
- // through the dlinfo() call, so only add additional space for the path
- // components explicitly added here.
- size_t library_path_size = info->dls_size + strlen(common_path);
- library_path = NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal);
- library_path[0] = '\0';
-
- // Construct the desired Java library path from the linker's library
- // search path.
- //
- // For compatibility, it is optimal that we insert the additional path
- // components specific to the Java VM after those components specified
- // in LD_LIBRARY_PATH (if any) but before those added by the ld.so
- // infrastructure.
- if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it.
- strcpy(library_path, common_path);
- } else {
- int inserted = 0;
- int i;
- for (i = 0; i < info->dls_cnt; i++, path++) {
- uint_t flags = path->dls_flags & LA_SER_MASK;
- if (((flags & LA_SER_LIBPATH) == 0) && !inserted) {
- strcat(library_path, common_path);
- strcat(library_path, os::path_separator());
- inserted = 1;
- }
- strcat(library_path, path->dls_name);
- strcat(library_path, os::path_separator());
- }
- // Eliminate trailing path separator.
- library_path[strlen(library_path)-1] = '\0';
- }
-
- // happens before argument parsing - can't use a trace flag
- // tty->print_raw("init_system_properties_values: native lib path: ");
- // tty->print_raw_cr(library_path);
-
- // Callee copies into its own buffer.
- Arguments::set_library_path(library_path);
-
- FREE_C_HEAP_ARRAY(char, library_path);
- FREE_C_HEAP_ARRAY(char, info);
- }
-
- // Extensions directories.
- sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
- Arguments::set_ext_dirs(buf);
-
- FREE_C_HEAP_ARRAY(char, buf);
-
-#undef SYS_EXT_DIR
-#undef EXTENSIONS_DIR
-}
-
-void os::breakpoint() {
- BREAKPOINT;
-}
-
-extern "C" void breakpoint() {
- // use debugger to set breakpoint here
-}
-
-static thread_t main_thread;
-
-// Thread start routine for all newly created threads
-extern "C" void* thread_native_entry(void* thread_addr) {
-
- Thread* thread = (Thread*)thread_addr;
-
- thread->record_stack_base_and_size();
-
- // Try to randomize the cache line index of hot stack frames.
- // This helps when threads of the same stack traces evict each other's
- // cache lines. The threads can be either from the same JVM instance, or
- // from different JVM instances. The benefit is especially true for
- // processors with hyperthreading technology.
- static int counter = 0;
- int pid = os::current_process_id();
- alloca(((pid ^ counter++) & 7) * 128);
-
- int prio;
-
- thread->initialize_thread_current();
-
- OSThread* osthr = thread->osthread();
-
- osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound
-
- log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").",
- os::current_thread_id());
-
- if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
- }
-
- // Our priority was set when we were created, and stored in the
- // osthread, but couldn't be passed through to our LWP until now.
- // So read back the priority and set it again.
-
- if (osthr->thread_id() != -1) {
- if (UseThreadPriorities) {
- int prio = osthr->native_priority();
- if (ThreadPriorityVerbose) {
- tty->print_cr("Starting Thread " INTPTR_FORMAT ", LWP is "
- INTPTR_FORMAT ", setting priority: %d\n",
- osthr->thread_id(), osthr->lwp_id(), prio);
- }
- os::set_native_priority(thread, prio);
- }
- } else if (ThreadPriorityVerbose) {
- warning("Can't set priority in _start routine, thread id hasn't been set\n");
- }
-
- assert(osthr->get_state() == RUNNABLE, "invalid os thread state");
-
- // initialize signal mask for this thread
- os::Solaris::hotspot_sigmask(thread);
-
- os::Solaris::init_thread_fpu_state();
- std::set_terminate(_handle_uncaught_cxx_exception);
-
- thread->call_run();
-
- // Note: at this point the thread object may already have deleted itself.
- // Do not dereference it from here on out.
-
- // One less thread is executing
- // When the VMThread gets here, the main thread may have already exited
- // which frees the CodeHeap containing the Atomic::dec code
- if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) {
- Atomic::dec(&os::Solaris::_os_thread_count);
- }
-
- log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id());
-
- if (UseDetachedThreads) {
- thr_exit(NULL);
- ShouldNotReachHere();
- }
- return NULL;
-}
-
-static OSThread* create_os_thread(Thread* thread, thread_t thread_id) {
- // Allocate the OSThread object
- OSThread* osthread = new OSThread(NULL, NULL);
- if (osthread == NULL) return NULL;
-
- // Store info on the Solaris thread into the OSThread
- osthread->set_thread_id(thread_id);
- osthread->set_lwp_id(_lwp_self());
-
- if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
- }
-
- if (ThreadPriorityVerbose) {
- tty->print_cr("In create_os_thread, Thread " INTPTR_FORMAT ", LWP is " INTPTR_FORMAT "\n",
- osthread->thread_id(), osthread->lwp_id());
- }
-
- // Initial thread state is INITIALIZED, not SUSPENDED
- osthread->set_state(INITIALIZED);
-
- return osthread;
-}
-
-void os::Solaris::hotspot_sigmask(Thread* thread) {
- //Save caller's signal mask
- sigset_t sigmask;
- pthread_sigmask(SIG_SETMASK, NULL, &sigmask);
- OSThread *osthread = thread->osthread();
- osthread->set_caller_sigmask(sigmask);
-
- pthread_sigmask(SIG_UNBLOCK, os::Solaris::unblocked_signals(), NULL);
- if (!ReduceSignalUsage) {
- if (thread->is_VM_thread()) {
- // Only the VM thread handles BREAK_SIGNAL ...
- pthread_sigmask(SIG_UNBLOCK, vm_signals(), NULL);
- } else {
- // ... all other threads block BREAK_SIGNAL
- assert(!sigismember(vm_signals(), SIGINT), "SIGINT should not be blocked");
- pthread_sigmask(SIG_BLOCK, vm_signals(), NULL);
- }
- }
-}
-
-bool os::create_attached_thread(JavaThread* thread) {
-#ifdef ASSERT
- thread->verify_not_published();
-#endif
- OSThread* osthread = create_os_thread(thread, thr_self());
- if (osthread == NULL) {
- return false;
- }
-
- // Initial thread state is RUNNABLE
- osthread->set_state(RUNNABLE);
- thread->set_osthread(osthread);
-
- // initialize signal mask for this thread
- // and save the caller's signal mask
- os::Solaris::hotspot_sigmask(thread);
-
- log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").",
- os::current_thread_id());
-
- return true;
-}
-
-bool os::create_main_thread(JavaThread* thread) {
-#ifdef ASSERT
- thread->verify_not_published();
-#endif
- if (_starting_thread == NULL) {
- _starting_thread = create_os_thread(thread, main_thread);
- if (_starting_thread == NULL) {
- return false;
- }
- }
-
- // The primodial thread is runnable from the start
- _starting_thread->set_state(RUNNABLE);
-
- thread->set_osthread(_starting_thread);
-
- // initialize signal mask for this thread
- // and save the caller's signal mask
- os::Solaris::hotspot_sigmask(thread);
-
- return true;
-}
-
-// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr()
-static char* describe_thr_create_attributes(char* buf, size_t buflen,
- size_t stacksize, long flags) {
- stringStream ss(buf, buflen);
- ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024);
- ss.print("flags: ");
- #define PRINT_FLAG(f) if (flags & f) ss.print( #f " ");
- #define ALL(X) \
- X(THR_SUSPENDED) \
- X(THR_DETACHED) \
- X(THR_BOUND) \
- X(THR_NEW_LWP) \
- X(THR_DAEMON)
- ALL(PRINT_FLAG)
- #undef ALL
- #undef PRINT_FLAG
- return buf;
-}
-
-// return default stack size for thr_type
-size_t os::Posix::default_stack_size(os::ThreadType thr_type) {
- // default stack size when not specified by caller is 1M (2M for LP64)
- size_t s = (BytesPerWord >> 2) * K * K;
- return s;
-}
-
-bool os::create_thread(Thread* thread, ThreadType thr_type,
- size_t req_stack_size) {
- // Allocate the OSThread object
- OSThread* osthread = new OSThread(NULL, NULL);
- if (osthread == NULL) {
- return false;
- }
-
- if (ThreadPriorityVerbose) {
- char *thrtyp;
- switch (thr_type) {
- case vm_thread:
- thrtyp = (char *)"vm";
- break;
- case cgc_thread:
- thrtyp = (char *)"cgc";
- break;
- case pgc_thread:
- thrtyp = (char *)"pgc";
- break;
- case java_thread:
- thrtyp = (char *)"java";
- break;
- case compiler_thread:
- thrtyp = (char *)"compiler";
- break;
- case watcher_thread:
- thrtyp = (char *)"watcher";
- break;
- default:
- thrtyp = (char *)"unknown";
- break;
- }
- tty->print_cr("In create_thread, creating a %s thread\n", thrtyp);
- }
-
- // calculate stack size if it's not specified by caller
- size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
-
- // Initial state is ALLOCATED but not INITIALIZED
- osthread->set_state(ALLOCATED);
-
- if (os::Solaris::_os_thread_count > os::Solaris::_os_thread_limit) {
- // We got lots of threads. Check if we still have some address space left.
- // Need to be at least 5Mb of unreserved address space. We do check by
- // trying to reserve some.
- const size_t VirtualMemoryBangSize = 20*K*K;
- char* mem = os::reserve_memory(VirtualMemoryBangSize);
- if (mem == NULL) {
- delete osthread;
- return false;
- } else {
- // Release the memory again
- os::release_memory(mem, VirtualMemoryBangSize);
- }
- }
-
- // Setup osthread because the child thread may need it.
- thread->set_osthread(osthread);
-
- // Create the Solaris thread
- thread_t tid = 0;
- long flags = (UseDetachedThreads ? THR_DETACHED : 0) | THR_SUSPENDED;
- int status;
-
- // Mark that we don't have an lwp or thread id yet.
- // In case we attempt to set the priority before the thread starts.
- osthread->set_lwp_id(-1);
- osthread->set_thread_id(-1);
-
- status = thr_create(NULL, stack_size, thread_native_entry, thread, flags, &tid);
-
- char buf[64];
- if (status == 0) {
- log_info(os, thread)("Thread started (tid: " UINTX_FORMAT ", attributes: %s). ",
- (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
- } else {
- log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.",
- os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
- // Log some OS information which might explain why creating the thread failed.
- log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
- LogStream st(Log(os, thread)::info());
- os::Posix::print_rlimit_info(&st);
- os::print_memory_info(&st);
- }
-
- if (status != 0) {
- thread->set_osthread(NULL);
- // Need to clean up stuff we've allocated so far
- delete osthread;
- return false;
- }
-
- Atomic::inc(&os::Solaris::_os_thread_count);
-
- // Store info on the Solaris thread into the OSThread
- osthread->set_thread_id(tid);
-
- // Remember that we created this thread so we can set priority on it
- osthread->set_vm_created();
-
- // Most thread types will set an explicit priority before starting the thread,
- // but for those that don't we need a valid value to read back in thread_native_entry.
- osthread->set_native_priority(NormPriority);
-
- // Initial thread state is INITIALIZED, not SUSPENDED
- osthread->set_state(INITIALIZED);
-
- // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain
- return true;
-}
-
-debug_only(static bool signal_sets_initialized = false);
-static sigset_t unblocked_sigs, vm_sigs;
-
-void os::Solaris::signal_sets_init() {
- // Should also have an assertion stating we are still single-threaded.
- assert(!signal_sets_initialized, "Already initialized");
- // Fill in signals that are necessarily unblocked for all threads in
- // the VM. Currently, we unblock the following signals:
- // SHUTDOWN{1,2,3}_SIGNAL: for shutdown hooks support (unless over-ridden
- // by -Xrs (=ReduceSignalUsage));
- // BREAK_SIGNAL which is unblocked only by the VM thread and blocked by all
- // other threads. The "ReduceSignalUsage" boolean tells us not to alter
- // the dispositions or masks wrt these signals.
- // Programs embedding the VM that want to use the above signals for their
- // own purposes must, at this time, use the "-Xrs" option to prevent
- // interference with shutdown hooks and BREAK_SIGNAL thread dumping.
- // (See bug 4345157, and other related bugs).
- // In reality, though, unblocking these signals is really a nop, since
- // these signals are not blocked by default.
- sigemptyset(&unblocked_sigs);
- sigaddset(&unblocked_sigs, SIGILL);
- sigaddset(&unblocked_sigs, SIGSEGV);
- sigaddset(&unblocked_sigs, SIGBUS);
- sigaddset(&unblocked_sigs, SIGFPE);
- sigaddset(&unblocked_sigs, ASYNC_SIGNAL);
-
- if (!ReduceSignalUsage) {
- if (!os::Posix::is_sig_ignored(SHUTDOWN1_SIGNAL)) {
- sigaddset(&unblocked_sigs, SHUTDOWN1_SIGNAL);
- }
- if (!os::Posix::is_sig_ignored(SHUTDOWN2_SIGNAL)) {
- sigaddset(&unblocked_sigs, SHUTDOWN2_SIGNAL);
- }
- if (!os::Posix::is_sig_ignored(SHUTDOWN3_SIGNAL)) {
- sigaddset(&unblocked_sigs, SHUTDOWN3_SIGNAL);
- }
- }
- // Fill in signals that are blocked by all but the VM thread.
- sigemptyset(&vm_sigs);
- if (!ReduceSignalUsage) {
- sigaddset(&vm_sigs, BREAK_SIGNAL);
- }
- debug_only(signal_sets_initialized = true);
-
- // For diagnostics only used in run_periodic_checks
- sigemptyset(&check_signal_done);
-}
-
-// These are signals that are unblocked while a thread is running Java.
-// (For some reason, they get blocked by default.)
-sigset_t* os::Solaris::unblocked_signals() {
- assert(signal_sets_initialized, "Not initialized");
- return &unblocked_sigs;
-}
-
-// These are the signals that are blocked while a (non-VM) thread is
-// running Java. Only the VM thread handles these signals.
-sigset_t* os::Solaris::vm_signals() {
- assert(signal_sets_initialized, "Not initialized");
- return &vm_sigs;
-}
-
-// CR 7190089: on Solaris, primordial thread's stack needs adjusting.
-// Without the adjustment, stack size is incorrect if stack is set to unlimited (ulimit -s unlimited).
-void os::Solaris::correct_stack_boundaries_for_primordial_thread(Thread* thr) {
- assert(is_primordial_thread(), "Call only for primordial thread");
-
- JavaThread* jt = (JavaThread *)thr;
- assert(jt != NULL, "Sanity check");
- size_t stack_size;
- address base = jt->stack_base();
- if (Arguments::created_by_java_launcher()) {
- // Use 2MB to allow for Solaris 7 64 bit mode.
- stack_size = JavaThread::stack_size_at_create() == 0
- ? 2048*K : JavaThread::stack_size_at_create();
-
- // There are rare cases when we may have already used more than
- // the basic stack size allotment before this method is invoked.
- // Attempt to allow for a normally sized java_stack.
- size_t current_stack_offset = (size_t)(base - (address)&stack_size);
- stack_size += ReservedSpace::page_align_size_down(current_stack_offset);
- } else {
- // 6269555: If we were not created by a Java launcher, i.e. if we are
- // running embedded in a native application, treat the primordial thread
- // as much like a native attached thread as possible. This means using
- // the current stack size from thr_stksegment(), unless it is too large
- // to reliably setup guard pages. A reasonable max size is 8MB.
- size_t current_size = os::current_stack_size();
- // This should never happen, but just in case....
- if (current_size == 0) current_size = 2 * K * K;
- stack_size = current_size > (8 * K * K) ? (8 * K * K) : current_size;
- }
- address bottom = align_up(base - stack_size, os::vm_page_size());;
- stack_size = (size_t)(base - bottom);
-
- assert(stack_size > 0, "Stack size calculation problem");
-
- if (stack_size > jt->stack_size()) {
-#ifndef PRODUCT
- struct rlimit limits;
- getrlimit(RLIMIT_STACK, &limits);
- size_t size = adjust_stack_size(base, (size_t)limits.rlim_cur);
- assert(size >= jt->stack_size(), "Stack size problem in main thread");
-#endif
- tty->print_cr("Stack size of %d Kb exceeds current limit of %d Kb.\n"
- "(Stack sizes are rounded up to a multiple of the system page size.)\n"
- "See limit(1) to increase the stack size limit.",
- stack_size / K, jt->stack_size() / K);
- vm_exit(1);
- }
- assert(jt->stack_size() >= stack_size,
- "Attempt to map more stack than was allocated");
- jt->set_stack_size(stack_size);
-
-}
-
-
-
-// Free Solaris resources related to the OSThread
-void os::free_thread(OSThread* osthread) {
- assert(osthread != NULL, "os::free_thread but osthread not set");
-
- // We are told to free resources of the argument thread,
- // but we can only really operate on the current thread.
- assert(Thread::current()->osthread() == osthread,
- "os::free_thread but not current thread");
-
- // Restore caller's signal mask
- sigset_t sigmask = osthread->caller_sigmask();
- pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
-
- delete osthread;
-}
-
-void os::pd_start_thread(Thread* thread) {
- int status = thr_continue(thread->osthread()->thread_id());
- assert_status(status == 0, status, "thr_continue failed");
-}
-
-
-intx os::current_thread_id() {
- return (intx)thr_self();
-}
-
-static pid_t _initial_pid = 0;
-
-int os::current_process_id() {
- return (int)(_initial_pid ? _initial_pid : getpid());
-}
-
-// gethrtime() should be monotonic according to the documentation,
-// but some virtualized platforms are known to break this guarantee.
-// getTimeNanos() must be guaranteed not to move backwards, so we
-// are forced to add a check here.
-inline hrtime_t getTimeNanos() {
- const hrtime_t now = gethrtime();
- const hrtime_t prev = max_hrtime;
- if (now <= prev) {
- return prev; // same or retrograde time;
- }
- const hrtime_t obsv = Atomic::cmpxchg(&max_hrtime, prev, now);
- assert(obsv >= prev, "invariant"); // Monotonicity
- // If the CAS succeeded then we're done and return "now".
- // If the CAS failed and the observed value "obsv" is >= now then
- // we should return "obsv". If the CAS failed and now > obsv > prv then
- // some other thread raced this thread and installed a new value, in which case
- // we could either (a) retry the entire operation, (b) retry trying to install now
- // or (c) just return obsv. We use (c). No loop is required although in some cases
- // we might discard a higher "now" value in deference to a slightly lower but freshly
- // installed obsv value. That's entirely benign -- it admits no new orderings compared
- // to (a) or (b) -- and greatly reduces coherence traffic.
- // We might also condition (c) on the magnitude of the delta between obsv and now.
- // Avoiding excessive CAS operations to hot RW locations is critical.
- // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
- return (prev == obsv) ? now : obsv;
-}
-
-// Time since start-up in seconds to a fine granularity.
-// Used by VMSelfDestructTimer and the MemProfiler.
-double os::elapsedTime() {
- return (double)(getTimeNanos() - first_hrtime) / (double)hrtime_hz;
-}
-
-jlong os::elapsed_counter() {
- return (jlong)(getTimeNanos() - first_hrtime);
-}
-
-jlong os::elapsed_frequency() {
- return hrtime_hz;
-}
-
-// Return the real, user, and system times in seconds from an
-// arbitrary fixed point in the past.
-bool os::getTimesSecs(double* process_real_time,
- double* process_user_time,
- double* process_system_time) {
- struct tms ticks;
- clock_t real_ticks = times(&ticks);
-
- if (real_ticks == (clock_t) (-1)) {
- return false;
- } else {
- double ticks_per_second = (double) clock_tics_per_sec;
- *process_user_time = ((double) ticks.tms_utime) / ticks_per_second;
- *process_system_time = ((double) ticks.tms_stime) / ticks_per_second;
- // For consistency return the real time from getTimeNanos()
- // converted to seconds.
- *process_real_time = ((double) getTimeNanos()) / ((double) NANOUNITS);
-
- return true;
- }
-}
-
-bool os::supports_vtime() { return true; }
-
-double os::elapsedVTime() {
- return (double)gethrvtime() / (double)hrtime_hz;
-}
-
-// Must return millis since Jan 1 1970 for JVM_CurrentTimeMillis
-jlong os::javaTimeMillis() {
- timeval t;
- if (gettimeofday(&t, NULL) == -1) {
- fatal("os::javaTimeMillis: gettimeofday (%s)", os::strerror(errno));
- }
- return jlong(t.tv_sec) * 1000 + jlong(t.tv_usec) / 1000;
-}
-
-// Must return seconds+nanos since Jan 1 1970. This must use the same
-// time source as javaTimeMillis and can't use get_nsec_fromepoch as
-// we need better than 1ms accuracy
-void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) {
- timeval t;
- if (gettimeofday(&t, NULL) == -1) {
- fatal("os::javaTimeSystemUTC: gettimeofday (%s)", os::strerror(errno));
- }
- seconds = jlong(t.tv_sec);
- nanos = jlong(t.tv_usec) * 1000;
-}
-
-
-jlong os::javaTimeNanos() {
- return (jlong)getTimeNanos();
-}
-
-void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
- info_ptr->max_value = ALL_64_BITS; // gethrtime() uses all 64 bits
- info_ptr->may_skip_backward = false; // not subject to resetting or drifting
- info_ptr->may_skip_forward = false; // not subject to resetting or drifting
- info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
-}
-
-char * os::local_time_string(char *buf, size_t buflen) {
- struct tm t;
- time_t long_time;
- time(&long_time);
- localtime_r(&long_time, &t);
- jio_snprintf(buf, buflen, "%d-%02d-%02d %02d:%02d:%02d",
- t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
- t.tm_hour, t.tm_min, t.tm_sec);
- return buf;
-}
-
-// Note: os::shutdown() might be called very early during initialization, or
-// called from signal handler. Before adding something to os::shutdown(), make
-// sure it is async-safe and can handle partially initialized VM.
-void os::shutdown() {
-
- // allow PerfMemory to attempt cleanup of any persistent resources
- perfMemory_exit();
-
- // needs to remove object in file system
- AttachListener::abort();
-
- // flush buffered output, finish log files
- ostream_abort();
-
- // Check for abort hook
- abort_hook_t abort_hook = Arguments::abort_hook();
- if (abort_hook != NULL) {
- abort_hook();
- }
-}
-
-// Note: os::abort() might be called very early during initialization, or
-// called from signal handler. Before adding something to os::abort(), make
-// sure it is async-safe and can handle partially initialized VM.
-void os::abort(bool dump_core, void* siginfo, const void* context) {
- os::shutdown();
- if (dump_core) {
- ::abort(); // dump core (for debugging)
- }
-
- ::exit(1);
-}
-
-// Die immediately, no exit hook, no abort hook, no cleanup.
-// Dump a core file, if possible, for debugging.
-void os::die() {
- if (TestUnresponsiveErrorHandler && !CreateCoredumpOnCrash) {
- // For TimeoutInErrorHandlingTest.java, we just kill the VM
- // and don't take the time to generate a core file.
- os::signal_raise(SIGKILL);
- } else {
- ::abort();
- }
-}
-
-// DLL functions
-
-const char* os::dll_file_extension() { return ".so"; }
-
-// This must be hard coded because it's the system's temporary
-// directory not the java application's temp directory, ala java.io.tmpdir.
-const char* os::get_temp_directory() { return "/tmp"; }
-
-// check if addr is inside libjvm.so
-bool os::address_is_in_vm(address addr) {
- static address libjvm_base_addr;
- Dl_info dlinfo;
-
- if (libjvm_base_addr == NULL) {
- if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) {
- libjvm_base_addr = (address)dlinfo.dli_fbase;
- }
- assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
- }
-
- if (dladdr((void *)addr, &dlinfo) != 0) {
- if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
- }
-
- return false;
-}
-
-typedef int (*dladdr1_func_type)(void *, Dl_info *, void **, int);
-static dladdr1_func_type dladdr1_func = NULL;
-
-bool os::dll_address_to_function_name(address addr, char *buf,
- int buflen, int * offset,
- bool demangle) {
- // buf is not optional, but offset is optional
- assert(buf != NULL, "sanity check");
-
- Dl_info dlinfo;
-
- // dladdr1_func was initialized in os::init()
- if (dladdr1_func != NULL) {
- // yes, we have dladdr1
-
- // Support for dladdr1 is checked at runtime; it may be
- // available even if the vm is built on a machine that does
- // not have dladdr1 support. Make sure there is a value for
- // RTLD_DL_SYMENT.
-#ifndef RTLD_DL_SYMENT
- #define RTLD_DL_SYMENT 1
-#endif
-#ifdef _LP64
- Elf64_Sym * info;
-#else
- Elf32_Sym * info;
-#endif
- if (dladdr1_func((void *)addr, &dlinfo, (void **)&info,
- RTLD_DL_SYMENT) != 0) {
- // see if we have a matching symbol that covers our address
- if (dlinfo.dli_saddr != NULL &&
- (char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
- if (dlinfo.dli_sname != NULL) {
- if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
- jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
- }
- if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
- return true;
- }
- }
- // no matching symbol so try for just file info
- if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
- if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
- buf, buflen, offset, dlinfo.dli_fname, demangle)) {
- return true;
- }
- }
- }
- buf[0] = '\0';
- if (offset != NULL) *offset = -1;
- return false;
- }
-
- // no, only dladdr is available
- if (dladdr((void *)addr, &dlinfo) != 0) {
- // see if we have a matching symbol
- if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
- if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
- jio_snprintf(buf, buflen, dlinfo.dli_sname);
- }
- if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
- return true;
- }
- // no matching symbol so try for just file info
- if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
- if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
- buf, buflen, offset, dlinfo.dli_fname, demangle)) {
- return true;
- }
- }
- }
- buf[0] = '\0';
- if (offset != NULL) *offset = -1;
- return false;
-}
-
-bool os::dll_address_to_library_name(address addr, char* buf,
- int buflen, int* offset) {
- // buf is not optional, but offset is optional
- assert(buf != NULL, "sanity check");
-
- Dl_info dlinfo;
-
- if (dladdr((void*)addr, &dlinfo) != 0) {
- if (dlinfo.dli_fname != NULL) {
- jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
- }
- if (dlinfo.dli_fbase != NULL && offset != NULL) {
- *offset = addr - (address)dlinfo.dli_fbase;
- }
- return true;
- }
-
- buf[0] = '\0';
- if (offset) *offset = -1;
- return false;
-}
-
-int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
- Dl_info dli;
- // Sanity check?
- if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 ||
- dli.dli_fname == NULL) {
- return 1;
- }
-
- void * handle = dlopen(dli.dli_fname, RTLD_LAZY);
- if (handle == NULL) {
- return 1;
- }
-
- Link_map *map;
- dlinfo(handle, RTLD_DI_LINKMAP, &map);
- if (map == NULL) {
- dlclose(handle);
- return 1;
- }
-
- while (map->l_prev != NULL) {
- map = map->l_prev;
- }
-
- while (map != NULL) {
- // Iterate through all map entries and call callback with fields of interest
- if(callback(map->l_name, (address)map->l_addr, (address)0, param)) {
- dlclose(handle);
- return 1;
- }
- map = map->l_next;
- }
-
- dlclose(handle);
- return 0;
-}
-
-int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) {
- outputStream * out = (outputStream *) param;
- out->print_cr(PTR_FORMAT " \t%s", base_address, name);
- return 0;
-}
-
-void os::print_dll_info(outputStream * st) {
- st->print_cr("Dynamic libraries:"); st->flush();
- if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) {
- st->print_cr("Error: Cannot print dynamic libraries.");
- }
-}
-
-static void change_endianness(Elf32_Half& val) {
- unsigned char *ptr = (unsigned char *)&val;
- unsigned char swp = ptr[0];
- ptr[0] = ptr[1];
- ptr[1] = swp;
-}
-
-// Loads .dll/.so and
-// in case of error it checks if .dll/.so was built for the
-// same architecture as Hotspot is running on
-
-void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
- log_info(os)("attempting shared library load of %s", filename);
-
- void * result= ::dlopen(filename, RTLD_LAZY);
- if (result != NULL) {
- // Successful loading
- Events::log(NULL, "Loaded shared library %s", filename);
- log_info(os)("shared library load of %s was successful", filename);
- return result;
- }
-
- Elf32_Ehdr elf_head;
- const char* error_report = ::dlerror();
- if (error_report == NULL) {
- error_report = "dlerror returned no error description";
- }
- if (ebuf != NULL && ebuflen > 0) {
- ::strncpy(ebuf, error_report, ebuflen-1);
- ebuf[ebuflen-1]='\0';
- }
-
- Events::log(NULL, "Loading shared library %s failed, %s", filename, error_report);
- log_info(os)("shared library load of %s failed, %s", filename, error_report);
-
- int diag_msg_max_length=ebuflen-strlen(ebuf);
- char* diag_msg_buf=ebuf+strlen(ebuf);
-
- if (diag_msg_max_length==0) {
- // No more space in ebuf for additional diagnostics message
- return NULL;
- }
-
-
- int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK);
-
- if (file_descriptor < 0) {
- // Can't open library, report dlerror() message
- return NULL;
- }
-
- bool failed_to_read_elf_head=
- (sizeof(elf_head)!=
- (::read(file_descriptor, &elf_head,sizeof(elf_head))));
-
- ::close(file_descriptor);
- if (failed_to_read_elf_head) {
- // file i/o error - report dlerror() msg
- return NULL;
- }
-
- if (elf_head.e_ident[EI_DATA] != LITTLE_ENDIAN_ONLY(ELFDATA2LSB) BIG_ENDIAN_ONLY(ELFDATA2MSB)) {
- // handle invalid/out of range endianness values
- if (elf_head.e_ident[EI_DATA] == 0 || elf_head.e_ident[EI_DATA] > 2) {
- return NULL;
- }
- change_endianness(elf_head.e_machine);
- }
-
- typedef struct {
- Elf32_Half code; // Actual value as defined in elf.h
- Elf32_Half compat_class; // Compatibility of archs at VM's sense
- unsigned char elf_class; // 32 or 64 bit
- unsigned char endianess; // MSB or LSB
- char* name; // String representation
- } arch_t;
-
- static const arch_t arch_array[]={
- {EM_386, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
- {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
- {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"},
- {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"},
- {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
- {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
- {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
- {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
- {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
- {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
- // we only support 64 bit z architecture
- {EM_S390, EM_S390, ELFCLASS64, ELFDATA2MSB, (char*)"IBM System/390"},
- {EM_AARCH64, EM_AARCH64, ELFCLASS64, ELFDATA2LSB, (char*)"AARCH64"}
- };
-
-#if (defined IA32)
- static Elf32_Half running_arch_code=EM_386;
-#elif (defined AMD64)
- static Elf32_Half running_arch_code=EM_X86_64;
-#elif (defined IA64)
- static Elf32_Half running_arch_code=EM_IA_64;
-#elif (defined __sparc) && (defined _LP64)
- static Elf32_Half running_arch_code=EM_SPARCV9;
-#elif (defined __sparc) && (!defined _LP64)
- static Elf32_Half running_arch_code=EM_SPARC;
-#elif (defined __powerpc64__)
- static Elf32_Half running_arch_code=EM_PPC64;
-#elif (defined __powerpc__)
- static Elf32_Half running_arch_code=EM_PPC;
-#elif (defined ARM)
- static Elf32_Half running_arch_code=EM_ARM;
-#else
- #error Method os::dll_load requires that one of following is defined:\
- IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM
-#endif
-
- // Identify compatibility class for VM's architecture and library's architecture
- // Obtain string descriptions for architectures
-
- arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL};
- int running_arch_index=-1;
-
- for (unsigned int i=0; i < ARRAY_SIZE(arch_array); i++) {
- if (running_arch_code == arch_array[i].code) {
- running_arch_index = i;
- }
- if (lib_arch.code == arch_array[i].code) {
- lib_arch.compat_class = arch_array[i].compat_class;
- lib_arch.name = arch_array[i].name;
- }
- }
-
- assert(running_arch_index != -1,
- "Didn't find running architecture code (running_arch_code) in arch_array");
- if (running_arch_index == -1) {
- // Even though running architecture detection failed
- // we may still continue with reporting dlerror() message
- return NULL;
- }
-
- if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) {
- if (lib_arch.name != NULL) {
- ::snprintf(diag_msg_buf, diag_msg_max_length-1,
- " (Possible cause: can't load %s .so on a %s platform)",
- lib_arch.name, arch_array[running_arch_index].name);
- } else {
- ::snprintf(diag_msg_buf, diag_msg_max_length-1,
- " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)",
- lib_arch.code, arch_array[running_arch_index].name);
- }
- return NULL;
- }
-
- if (lib_arch.endianess != arch_array[running_arch_index].endianess) {
- ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)");
- return NULL;
- }
-
- // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit
- if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) {
- ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)");
- return NULL;
- }
-
- if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) {
- ::snprintf(diag_msg_buf, diag_msg_max_length-1,
- " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)",
- (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32);
- return NULL;
- }
-
- return NULL;
-}
-
-void* os::dll_lookup(void* handle, const char* name) {
- return dlsym(handle, name);
-}
-
-void* os::get_default_process_handle() {
- return (void*)::dlopen(NULL, RTLD_LAZY);
-}
-
-static inline time_t get_mtime(const char* filename) {
- struct stat st;
- int ret = os::stat(filename, &st);
- assert(ret == 0, "failed to stat() file '%s': %s", filename, os::strerror(errno));
- return st.st_mtime;
-}
-
-int os::compare_file_modified_times(const char* file1, const char* file2) {
- time_t t1 = get_mtime(file1);
- time_t t2 = get_mtime(file2);
- return t1 - t2;
-}
-
-static bool _print_ascii_file(const char* filename, outputStream* st) {
- int fd = ::open(filename, O_RDONLY);
- if (fd == -1) {
- return false;
- }
-
- char buf[32];
- int bytes;
- while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) {
- st->print_raw(buf, bytes);
- }
-
- ::close(fd);
-
- return true;
-}
-
-void os::print_os_info_brief(outputStream* st) {
- os::Solaris::print_distro_info(st);
-
- os::Posix::print_uname_info(st);
-
- os::Solaris::print_libversion_info(st);
-}
-
-void os::print_os_info(outputStream* st) {
- st->print("OS:");
-
- os::Solaris::print_distro_info(st);
-
- os::Posix::print_uname_info(st);
-
- os::Posix::print_uptime_info(st);
-
- os::Solaris::print_libversion_info(st);
-
- os::Posix::print_rlimit_info(st);
-
- os::Posix::print_load_average(st);
-}
-
-void os::Solaris::print_distro_info(outputStream* st) {
- if (!_print_ascii_file("/etc/release", st)) {
- st->print("Solaris");
- }
- st->cr();
-}
-
-void os::get_summary_os_info(char* buf, size_t buflen) {
- strncpy(buf, "Solaris", buflen); // default to plain solaris
- FILE* fp = fopen("/etc/release", "r");
- if (fp != NULL) {
- char tmp[256];
- // Only get the first line and chop out everything but the os name.
- if (fgets(tmp, sizeof(tmp), fp)) {
- char* ptr = tmp;
- // skip past whitespace characters
- while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++;
- if (*ptr != '\0') {
- char* nl = strchr(ptr, '\n');
- if (nl != NULL) *nl = '\0';
- strncpy(buf, ptr, buflen);
- }
- }
- fclose(fp);
- }
-}
-
-void os::Solaris::print_libversion_info(outputStream* st) {
- st->print(" (T2 libthread)");
- st->cr();
-}
-
-static bool check_addr0(outputStream* st) {
- jboolean status = false;
- const int read_chunk = 200;
- int ret = 0;
- int nmap = 0;
- int fd = ::open("/proc/self/map",O_RDONLY);
- if (fd >= 0) {
- prmap_t *p = NULL;
- char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t));
- if (NULL == mbuff) {
- ::close(fd);
- return status;
- }
- while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) {
- //check if read() has not read partial data
- if( 0 != ret % sizeof(prmap_t)){
- break;
- }
- nmap = ret / sizeof(prmap_t);
- p = (prmap_t *)mbuff;
- for(int i = 0; i < nmap; i++){
- if (p->pr_vaddr == 0x0) {
- st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024);
- st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname);
- st->print("Access: ");
- st->print("%s",(p->pr_mflags & MA_READ) ? "r" : "-");
- st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-");
- st->print("%s",(p->pr_mflags & MA_EXEC) ? "x" : "-");
- st->cr();
- status = true;
- }
- p++;
- }
- }
- free(mbuff);
- ::close(fd);
- }
- return status;
-}
-
-void os::get_summary_cpu_info(char* buf, size_t buflen) {
- // Get MHz with system call. We don't seem to already have this.
- processor_info_t stats;
- processorid_t id = getcpuid();
- int clock = 0;
- if (processor_info(id, &stats) != -1) {
- clock = stats.pi_clock; // pi_processor_type isn't more informative than below
- }
-#ifdef AMD64
- snprintf(buf, buflen, "x86 64 bit %d MHz", clock);
-#else
- // must be sparc
- snprintf(buf, buflen, "Sparcv9 64 bit %d MHz", clock);
-#endif
-}
-
-void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
- // Nothing to do for now.
-}
-
-void os::print_memory_info(outputStream* st) {
- st->print("Memory:");
- st->print(" %dk page", os::vm_page_size()>>10);
- st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10);
- st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10);
- st->cr();
- (void) check_addr0(st);
-}
-
-// Moved from whole group, because we need them here for diagnostic
-// prints.
-static int Maxsignum = 0;
-static int *ourSigFlags = NULL;
-
-int os::Solaris::get_our_sigflags(int sig) {
- assert(ourSigFlags!=NULL, "signal data structure not initialized");
- assert(sig > 0 && sig < Maxsignum, "vm signal out of expected range");
- return ourSigFlags[sig];
-}
-
-void os::Solaris::set_our_sigflags(int sig, int flags) {
- assert(ourSigFlags!=NULL, "signal data structure not initialized");
- assert(sig > 0 && sig < Maxsignum, "vm signal out of expected range");
- ourSigFlags[sig] = flags;
-}
-
-
-static const char* get_signal_handler_name(address handler,
- char* buf, int buflen) {
- int offset;
- bool found = os::dll_address_to_library_name(handler, buf, buflen, &offset);
- if (found) {
- // skip directory names
- const char *p1, *p2;
- p1 = buf;
- size_t len = strlen(os::file_separator());
- while ((p2 = strstr(p1, os::file_separator())) != NULL) p1 = p2 + len;
- jio_snprintf(buf, buflen, "%s+0x%x", p1, offset);
- } else {
- jio_snprintf(buf, buflen, PTR_FORMAT, handler);
- }
- return buf;
-}
-
-static void print_signal_handler(outputStream* st, int sig,
- char* buf, size_t buflen) {
- struct sigaction sa;
-
- sigaction(sig, NULL, &sa);
-
- st->print("%s: ", os::exception_name(sig, buf, buflen));
-
- address handler = (sa.sa_flags & SA_SIGINFO)
- ? CAST_FROM_FN_PTR(address, sa.sa_sigaction)
- : CAST_FROM_FN_PTR(address, sa.sa_handler);
-
- if (handler == CAST_FROM_FN_PTR(address, SIG_DFL)) {
- st->print("SIG_DFL");
- } else if (handler == CAST_FROM_FN_PTR(address, SIG_IGN)) {
- st->print("SIG_IGN");
- } else {
- st->print("[%s]", get_signal_handler_name(handler, buf, buflen));
- }
-
- st->print(", sa_mask[0]=");
- os::Posix::print_signal_set_short(st, &sa.sa_mask);
-
- address rh = VMError::get_resetted_sighandler(sig);
- // May be, handler was resetted by VMError?
- if (rh != NULL) {
- handler = rh;
- sa.sa_flags = VMError::get_resetted_sigflags(sig);
- }
-
- st->print(", sa_flags=");
- os::Posix::print_sa_flags(st, sa.sa_flags);
-
- // Check: is it our handler?
- if (handler == CAST_FROM_FN_PTR(address, signalHandler)) {
- // It is our signal handler
- // check for flags
- if (sa.sa_flags != os::Solaris::get_our_sigflags(sig)) {
- st->print(
- ", flags was changed from " PTR32_FORMAT ", consider using jsig library",
- os::Solaris::get_our_sigflags(sig));
- }
- }
- st->cr();
-}
-
-void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) {
- st->print_cr("Signal Handlers:");
- print_signal_handler(st, SIGSEGV, buf, buflen);
- print_signal_handler(st, SIGBUS , buf, buflen);
- print_signal_handler(st, SIGFPE , buf, buflen);
- print_signal_handler(st, SIGPIPE, buf, buflen);
- print_signal_handler(st, SIGXFSZ, buf, buflen);
- print_signal_handler(st, SIGILL , buf, buflen);
- print_signal_handler(st, ASYNC_SIGNAL, buf, buflen);
- print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
- print_signal_handler(st, SHUTDOWN1_SIGNAL , buf, buflen);
- print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
- print_signal_handler(st, SHUTDOWN3_SIGNAL, buf, buflen);
-}
-
-static char saved_jvm_path[MAXPATHLEN] = { 0 };
-
-// Find the full path to the current module, libjvm.so
-void os::jvm_path(char *buf, jint buflen) {
- // Error checking.
- if (buflen < MAXPATHLEN) {
- assert(false, "must use a large-enough buffer");
- buf[0] = '\0';
- return;
- }
- // Lazy resolve the path to current module.
- if (saved_jvm_path[0] != 0) {
- strcpy(buf, saved_jvm_path);
- return;
- }
-
- Dl_info dlinfo;
- int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo);
- assert(ret != 0, "cannot locate libjvm");
- if (ret != 0 && dlinfo.dli_fname != NULL) {
- if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) {
- return;
- }
- } else {
- buf[0] = '\0';
- return;
- }
-
- if (Arguments::sun_java_launcher_is_altjvm()) {
- // Support for the java launcher's '-XXaltjvm=' option. Typical
- // value for buf is "/jre/lib///libjvm.so".
- // If "/jre/lib/" appears at the right place in the string, then
- // assume we are installed in a JDK and we're done. Otherwise, check
- // for a JAVA_HOME environment variable and fix up the path so it
- // looks like libjvm.so is installed there (append a fake suffix
- // hotspot/libjvm.so).
- const char *p = buf + strlen(buf) - 1;
- for (int count = 0; p > buf && count < 5; ++count) {
- for (--p; p > buf && *p != '/'; --p)
- /* empty */ ;
- }
-
- if (strncmp(p, "/jre/lib/", 9) != 0) {
- // Look for JAVA_HOME in the environment.
- char* java_home_var = ::getenv("JAVA_HOME");
- if (java_home_var != NULL && java_home_var[0] != 0) {
- char* jrelib_p;
- int len;
-
- // Check the current module name "libjvm.so".
- p = strrchr(buf, '/');
- assert(strstr(p, "/libjvm") == p, "invalid library name");
-
- if (os::Posix::realpath(java_home_var, buf, buflen) == NULL) {
- return;
- }
- // determine if this is a legacy image or modules image
- // modules image doesn't have "jre" subdirectory
- len = strlen(buf);
- assert(len < buflen, "Ran out of buffer space");
- jrelib_p = buf + len;
- snprintf(jrelib_p, buflen-len, "/jre/lib");
- if (0 != access(buf, F_OK)) {
- snprintf(jrelib_p, buflen-len, "/lib");
- }
-
- if (0 == access(buf, F_OK)) {
- // Use current module name "libjvm.so"
- len = strlen(buf);
- snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
- } else {
- // Go back to path of .so
- if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) {
- return;
- }
- }
- }
- }
- }
-
- strncpy(saved_jvm_path, buf, MAXPATHLEN);
- saved_jvm_path[MAXPATHLEN - 1] = '\0';
-}
-
-
-void os::print_jni_name_prefix_on(outputStream* st, int args_size) {
- // no prefix required, not even "_"
-}
-
-
-void os::print_jni_name_suffix_on(outputStream* st, int args_size) {
- // no suffix required
-}
-
-// sun.misc.Signal
-
-extern "C" {
- static void UserHandler(int sig, void *siginfo, void *context) {
- // Ctrl-C is pressed during error reporting, likely because the error
- // handler fails to abort. Let VM die immediately.
- if (sig == SIGINT && VMError::is_error_reported()) {
- os::die();
- }
-
- os::signal_notify(sig);
- // We do not need to reinstate the signal handler each time...
- }
-}
-
-void* os::user_handler() {
- return CAST_FROM_FN_PTR(void*, UserHandler);
-}
-
-extern "C" {
- typedef void (*sa_handler_t)(int);
- typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
-}
-
-void* os::signal(int signal_number, void* handler) {
- struct sigaction sigAct, oldSigAct;
- sigfillset(&(sigAct.sa_mask));
- sigAct.sa_flags = SA_RESTART & ~SA_RESETHAND;
- sigAct.sa_flags |= SA_SIGINFO;
- sigAct.sa_handler = CAST_TO_FN_PTR(sa_handler_t, handler);
-
- if (sigaction(signal_number, &sigAct, &oldSigAct)) {
- // -1 means registration failed
- return (void *)-1;
- }
-
- return CAST_FROM_FN_PTR(void*, oldSigAct.sa_handler);
-}
-
-void os::signal_raise(int signal_number) {
- raise(signal_number);
-}
-
-// The following code is moved from os.cpp for making this
-// code platform specific, which it is by its very nature.
-
-// a counter for each possible signal value
-static int Sigexit = 0;
-static jint *pending_signals = NULL;
-static int *preinstalled_sigs = NULL;
-static struct sigaction *chainedsigactions = NULL;
-static Semaphore* sig_sem = NULL;
-
-int os::sigexitnum_pd() {
- assert(Sigexit > 0, "signal memory not yet initialized");
- return Sigexit;
-}
-
-void os::Solaris::init_signal_mem() {
- // Initialize signal structures
- Maxsignum = SIGRTMAX;
- Sigexit = Maxsignum+1;
- assert(Maxsignum >0, "Unable to obtain max signal number");
-
- // Initialize signal structures
- // pending_signals has one int per signal
- // The additional signal is for SIGEXIT - exit signal to signal_thread
- pending_signals = (jint *)os::malloc(sizeof(jint) * (Sigexit+1), mtInternal);
- memset(pending_signals, 0, (sizeof(jint) * (Sigexit+1)));
-
- if (UseSignalChaining) {
- chainedsigactions = (struct sigaction *)malloc(sizeof(struct sigaction)
- * (Maxsignum + 1), mtInternal);
- memset(chainedsigactions, 0, (sizeof(struct sigaction) * (Maxsignum + 1)));
- preinstalled_sigs = (int *)os::malloc(sizeof(int) * (Maxsignum + 1), mtInternal);
- memset(preinstalled_sigs, 0, (sizeof(int) * (Maxsignum + 1)));
- }
- ourSigFlags = (int*)malloc(sizeof(int) * (Maxsignum + 1), mtInternal);
- memset(ourSigFlags, 0, sizeof(int) * (Maxsignum + 1));
-}
-
-static void jdk_misc_signal_init() {
- // Initialize signal semaphore
- sig_sem = new Semaphore();
-}
-
-void os::signal_notify(int sig) {
- if (sig_sem != NULL) {
- Atomic::inc(&pending_signals[sig]);
- sig_sem->signal();
- } else {
- // Signal thread is not created with ReduceSignalUsage and jdk_misc_signal_init
- // initialization isn't called.
- assert(ReduceSignalUsage, "signal semaphore should be created");
- }
-}
-
-static int check_pending_signals() {
- int ret;
- while (true) {
- for (int i = 0; i < Sigexit + 1; i++) {
- jint n = pending_signals[i];
- if (n > 0 && n == Atomic::cmpxchg(&pending_signals[i], n, n - 1)) {
- return i;
- }
- }
- JavaThread *thread = JavaThread::current();
- ThreadBlockInVM tbivm(thread);
-
- bool threadIsSuspended;
- do {
- thread->set_suspend_equivalent();
- sig_sem->wait();
-
- // were we externally suspended while we were waiting?
- threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
- if (threadIsSuspended) {
- // The semaphore has been incremented, but while we were waiting
- // another thread suspended us. We don't want to continue running
- // while suspended because that would surprise the thread that
- // suspended us.
- sig_sem->signal();
-
- thread->java_suspend_self();
- }
- } while (threadIsSuspended);
- }
-}
-
-int os::signal_wait() {
- return check_pending_signals();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Virtual Memory
-
-static int page_size = -1;
-
-int os::vm_page_size() {
- assert(page_size != -1, "must call os::init");
- return page_size;
-}
-
-// Solaris allocates memory by pages.
-int os::vm_allocation_granularity() {
- assert(page_size != -1, "must call os::init");
- return page_size;
-}
-
-static bool recoverable_mmap_error(int err) {
- // See if the error is one we can let the caller handle. This
- // list of errno values comes from the Solaris mmap(2) man page.
- switch (err) {
- case EBADF:
- case EINVAL:
- case ENOTSUP:
- // let the caller deal with these errors
- return true;
-
- default:
- // Any remaining errors on this OS can cause our reserved mapping
- // to be lost. That can cause confusion where different data
- // structures think they have the same memory mapped. The worst
- // scenario is if both the VM and a library think they have the
- // same memory mapped.
- return false;
- }
-}
-
-static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec,
- int err) {
- warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
- ", %d) failed; error='%s' (errno=%d)", addr, bytes, exec,
- os::strerror(err), err);
-}
-
-static void warn_fail_commit_memory(char* addr, size_t bytes,
- size_t alignment_hint, bool exec,
- int err) {
- warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
- ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, bytes,
- alignment_hint, exec, os::strerror(err), err);
-}
-
-int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) {
- int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
- size_t size = bytes;
- char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot);
- if (res != NULL) {
- if (UseNUMAInterleaving) {
- numa_make_global(addr, bytes);
- }
- return 0;
- }
-
- int err = errno; // save errno from mmap() call in mmap_chunk()
-
- if (!recoverable_mmap_error(err)) {
- warn_fail_commit_memory(addr, bytes, exec, err);
- vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "committing reserved memory.");
- }
-
- return err;
-}
-
-bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) {
- return Solaris::commit_memory_impl(addr, bytes, exec) == 0;
-}
-
-void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec,
- const char* mesg) {
- assert(mesg != NULL, "mesg must be specified");
- int err = os::Solaris::commit_memory_impl(addr, bytes, exec);
- if (err != 0) {
- // the caller wants all commit errors to exit with the specified mesg:
- warn_fail_commit_memory(addr, bytes, exec, err);
- vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg);
- }
-}
-
-size_t os::Solaris::page_size_for_alignment(size_t alignment) {
- assert(is_aligned(alignment, (size_t) vm_page_size()),
- SIZE_FORMAT " is not aligned to " SIZE_FORMAT,
- alignment, (size_t) vm_page_size());
-
- for (int i = 0; _page_sizes[i] != 0; i++) {
- if (is_aligned(alignment, _page_sizes[i])) {
- return _page_sizes[i];
- }
- }
-
- return (size_t) vm_page_size();
-}
-
-int os::Solaris::commit_memory_impl(char* addr, size_t bytes,
- size_t alignment_hint, bool exec) {
- int err = Solaris::commit_memory_impl(addr, bytes, exec);
- if (err == 0 && UseLargePages && alignment_hint > 0) {
- assert(is_aligned(bytes, alignment_hint),
- SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint);
-
- // The syscall memcntl requires an exact page size (see man memcntl for details).
- size_t page_size = page_size_for_alignment(alignment_hint);
- if (page_size > (size_t) vm_page_size()) {
- (void)Solaris::setup_large_pages(addr, bytes, page_size);
- }
- }
- return err;
-}
-
-bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint,
- bool exec) {
- return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0;
-}
-
-void os::pd_commit_memory_or_exit(char* addr, size_t bytes,
- size_t alignment_hint, bool exec,
- const char* mesg) {
- assert(mesg != NULL, "mesg must be specified");
- int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec);
- if (err != 0) {
- // the caller wants all commit errors to exit with the specified mesg:
- warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err);
- vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg);
- }
-}
-
-// Uncommit the pages in a specified region.
-void os::pd_free_memory(char* addr, size_t bytes, size_t alignment_hint) {
- if (madvise(addr, bytes, MADV_FREE) < 0) {
- debug_only(warning("MADV_FREE failed."));
- return;
- }
-}
-
-bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
- return os::commit_memory(addr, size, !ExecMem);
-}
-
-bool os::remove_stack_guard_pages(char* addr, size_t size) {
- return os::uncommit_memory(addr, size);
-}
-
-// Change the page size in a given range.
-void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
- assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned.");
- assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned.");
- if (UseLargePages) {
- size_t page_size = Solaris::page_size_for_alignment(alignment_hint);
- if (page_size > (size_t) vm_page_size()) {
- Solaris::setup_large_pages(addr, bytes, page_size);
- }
- }
-}
-
-// Tell the OS to make the range local to the first-touching LWP
-void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
- assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
- if (madvise(addr, bytes, MADV_ACCESS_LWP) < 0) {
- debug_only(warning("MADV_ACCESS_LWP failed."));
- }
-}
-
-// Tell the OS that this range would be accessed from different LWPs.
-void os::numa_make_global(char *addr, size_t bytes) {
- assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
- if (madvise(addr, bytes, MADV_ACCESS_MANY) < 0) {
- debug_only(warning("MADV_ACCESS_MANY failed."));
- }
-}
-
-// Get the number of the locality groups.
-size_t os::numa_get_groups_num() {
- size_t n = Solaris::lgrp_nlgrps(Solaris::lgrp_cookie());
- return n != -1 ? n : 1;
-}
-
-// Get a list of leaf locality groups. A leaf lgroup is group that
-// doesn't have any children. Typical leaf group is a CPU or a CPU/memory
-// board. An LWP is assigned to one of these groups upon creation.
-size_t os::numa_get_leaf_groups(int *ids, size_t size) {
- if ((ids[0] = Solaris::lgrp_root(Solaris::lgrp_cookie())) == -1) {
- ids[0] = 0;
- return 1;
- }
- int result_size = 0, top = 1, bottom = 0, cur = 0;
- for (int k = 0; k < size; k++) {
- int r = Solaris::lgrp_children(Solaris::lgrp_cookie(), ids[cur],
- (Solaris::lgrp_id_t*)&ids[top], size - top);
- if (r == -1) {
- ids[0] = 0;
- return 1;
- }
- if (!r) {
- // That's a leaf node.
- assert(bottom <= cur, "Sanity check");
- // Check if the node has memory
- if (Solaris::lgrp_resources(Solaris::lgrp_cookie(), ids[cur],
- NULL, 0, LGRP_RSRC_MEM) > 0) {
- ids[bottom++] = ids[cur];
- }
- }
- top += r;
- cur++;
- }
- if (bottom == 0) {
- // Handle a situation, when the OS reports no memory available.
- // Assume UMA architecture.
- ids[0] = 0;
- return 1;
- }
- return bottom;
-}
-
-// Detect the topology change. Typically happens during CPU plugging-unplugging.
-bool os::numa_topology_changed() {
- int is_stale = Solaris::lgrp_cookie_stale(Solaris::lgrp_cookie());
- if (is_stale != -1 && is_stale) {
- Solaris::lgrp_fini(Solaris::lgrp_cookie());
- Solaris::lgrp_cookie_t c = Solaris::lgrp_init(Solaris::LGRP_VIEW_CALLER);
- assert(c != 0, "Failure to initialize LGRP API");
- Solaris::set_lgrp_cookie(c);
- return true;
- }
- return false;
-}
-
-// Get the group id of the current LWP.
-int os::numa_get_group_id() {
- int lgrp_id = Solaris::lgrp_home(P_LWPID, P_MYID);
- if (lgrp_id == -1) {
- return 0;
- }
- const int size = os::numa_get_groups_num();
- int *ids = (int*)alloca(size * sizeof(int));
-
- // Get the ids of all lgroups with memory; r is the count.
- int r = Solaris::lgrp_resources(Solaris::lgrp_cookie(), lgrp_id,
- (Solaris::lgrp_id_t*)ids, size, LGRP_RSRC_MEM);
- if (r <= 0) {
- return 0;
- }
- return ids[os::random() % r];
-}
-
-int os::numa_get_group_id_for_address(const void* address) {
- return 0;
-}
-
-// Request information about the page.
-bool os::get_page_info(char *start, page_info* info) {
- const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE };
- uint64_t addr = (uintptr_t)start;
- uint64_t outdata[2];
- uint_t validity = 0;
-
- if (meminfo(&addr, 1, info_types, 2, outdata, &validity) < 0) {
- return false;
- }
-
- info->size = 0;
- info->lgrp_id = -1;
-
- if ((validity & 1) != 0) {
- if ((validity & 2) != 0) {
- info->lgrp_id = outdata[0];
- }
- if ((validity & 4) != 0) {
- info->size = outdata[1];
- }
- return true;
- }
- return false;
-}
-
-// Scan the pages from start to end until a page different than
-// the one described in the info parameter is encountered.
-char *os::scan_pages(char *start, char* end, page_info* page_expected,
- page_info* page_found) {
- const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE };
- const size_t types = sizeof(info_types) / sizeof(info_types[0]);
- uint64_t addrs[MAX_MEMINFO_CNT], outdata[types * MAX_MEMINFO_CNT + 1];
- uint_t validity[MAX_MEMINFO_CNT];
-
- size_t page_size = MAX2((size_t)os::vm_page_size(), page_expected->size);
- uint64_t p = (uint64_t)start;
- while (p < (uint64_t)end) {
- addrs[0] = p;
- size_t addrs_count = 1;
- while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) {
- addrs[addrs_count] = addrs[addrs_count - 1] + page_size;
- addrs_count++;
- }
-
- if (meminfo(addrs, addrs_count, info_types, types, outdata, validity) < 0) {
- return NULL;
- }
-
- size_t i = 0;
- for (; i < addrs_count; i++) {
- if ((validity[i] & 1) != 0) {
- if ((validity[i] & 4) != 0) {
- if (outdata[types * i + 1] != page_expected->size) {
- break;
- }
- } else if (page_expected->size != 0) {
- break;
- }
-
- if ((validity[i] & 2) != 0 && page_expected->lgrp_id > 0) {
- if (outdata[types * i] != page_expected->lgrp_id) {
- break;
- }
- }
- } else {
- return NULL;
- }
- }
-
- if (i < addrs_count) {
- if ((validity[i] & 2) != 0) {
- page_found->lgrp_id = outdata[types * i];
- } else {
- page_found->lgrp_id = -1;
- }
- if ((validity[i] & 4) != 0) {
- page_found->size = outdata[types * i + 1];
- } else {
- page_found->size = 0;
- }
- return (char*)addrs[i];
- }
-
- p = addrs[addrs_count - 1] + page_size;
- }
- return end;
-}
-
-bool os::pd_uncommit_memory(char* addr, size_t bytes) {
- size_t size = bytes;
- // Map uncommitted pages PROT_NONE so we fail early if we touch an
- // uncommitted page. Otherwise, the read/write might succeed if we
- // have enough swap space to back the physical page.
- return
- NULL != Solaris::mmap_chunk(addr, size,
- MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE,
- PROT_NONE);
-}
-
-char* os::Solaris::mmap_chunk(char *addr, size_t size, int flags, int prot) {
- char *b = (char *)mmap(addr, size, prot, flags, os::Solaris::_dev_zero_fd, 0);
-
- if (b == MAP_FAILED) {
- return NULL;
- }
- return b;
-}
-
-char* os::Solaris::anon_mmap(char* requested_addr, size_t bytes,
- size_t alignment_hint, bool fixed) {
- char* addr = requested_addr;
- int flags = MAP_PRIVATE | MAP_NORESERVE;
-
- assert(!(fixed && (alignment_hint > 0)),
- "alignment hint meaningless with fixed mmap");
-
- if (fixed) {
- flags |= MAP_FIXED;
- } else if (alignment_hint > (size_t) vm_page_size()) {
- flags |= MAP_ALIGN;
- addr = (char*) alignment_hint;
- }
-
- // Map uncommitted pages PROT_NONE so we fail early if we touch an
- // uncommitted page. Otherwise, the read/write might succeed if we
- // have enough swap space to back the physical page.
- return mmap_chunk(addr, bytes, flags, PROT_NONE);
-}
-
-char* os::pd_reserve_memory(size_t bytes, char* requested_addr,
- size_t alignment_hint) {
- char* addr = Solaris::anon_mmap(requested_addr, bytes, alignment_hint,
- (requested_addr != NULL));
-
- guarantee(requested_addr == NULL || requested_addr == addr,
- "OS failed to return requested mmap address.");
- return addr;
-}
-
-char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr, int file_desc) {
- assert(file_desc >= 0, "file_desc is not valid");
- char* result = pd_attempt_reserve_memory_at(bytes, requested_addr);
- if (result != NULL) {
- if (replace_existing_mapping_with_file_mapping(result, bytes, file_desc) == NULL) {
- vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory"));
- }
- }
- return result;
-}
-
-// Reserve memory at an arbitrary address, only if that area is
-// available (and not reserved for something else).
-
-char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) {
- // Assert only that the size is a multiple of the page size, since
- // that's all that mmap requires, and since that's all we really know
- // about at this low abstraction level. If we need higher alignment,
- // we can either pass an alignment to this method or verify alignment
- // in one of the methods further up the call chain. See bug 5044738.
- assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block");
-
- // Since snv_84, Solaris attempts to honor the address hint - see 5003415.
- char* addr = Solaris::anon_mmap(requested_addr, bytes, 0, false);
-
- volatile int err = errno;
- if (addr == requested_addr) {
- return addr;
- }
-
- if (addr != NULL) {
- pd_unmap_memory(addr, bytes);
- }
-
- return NULL;
-}
-
-bool os::pd_release_memory(char* addr, size_t bytes) {
- size_t size = bytes;
- return munmap(addr, size) == 0;
-}
-
-static bool solaris_mprotect(char* addr, size_t bytes, int prot) {
- assert(addr == (char*)align_down((uintptr_t)addr, os::vm_page_size()),
- "addr must be page aligned");
- Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+bytes), prot);
- int retVal = mprotect(addr, bytes, prot);
- return retVal == 0;
-}
-
-// Protect memory (Used to pass readonly pages through
-// JNI GetArrayElements with empty arrays.)
-// Also, used for serialization page and for compressed oops null pointer
-// checking.
-bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
- bool is_committed) {
- unsigned int p = 0;
- switch (prot) {
- case MEM_PROT_NONE: p = PROT_NONE; break;
- case MEM_PROT_READ: p = PROT_READ; break;
- case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break;
- case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break;
- default:
- ShouldNotReachHere();
- }
- // is_committed is unused.
- return solaris_mprotect(addr, bytes, p);
-}
-
-// guard_memory and unguard_memory only happens within stack guard pages.
-// Since ISM pertains only to the heap, guard and unguard memory should not
-/// happen with an ISM region.
-bool os::guard_memory(char* addr, size_t bytes) {
- return solaris_mprotect(addr, bytes, PROT_NONE);
-}
-
-bool os::unguard_memory(char* addr, size_t bytes) {
- return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE);
-}
-
-// Large page support
-static size_t _large_page_size = 0;
-
-// Insertion sort for small arrays (descending order).
-static void insertion_sort_descending(size_t* array, int len) {
- for (int i = 0; i < len; i++) {
- size_t val = array[i];
- for (size_t key = i; key > 0 && array[key - 1] < val; --key) {
- size_t tmp = array[key];
- array[key] = array[key - 1];
- array[key - 1] = tmp;
- }
- }
-}
-
-bool os::Solaris::mpss_sanity_check(bool warn, size_t* page_size) {
- const unsigned int usable_count = VM_Version::page_size_count();
- if (usable_count == 1) {
- return false;
- }
-
- // Find the right getpagesizes interface. When solaris 11 is the minimum
- // build platform, getpagesizes() (without the '2') can be called directly.
- typedef int (*gps_t)(size_t[], int);
- gps_t gps_func = CAST_TO_FN_PTR(gps_t, dlsym(RTLD_DEFAULT, "getpagesizes2"));
- if (gps_func == NULL) {
- gps_func = CAST_TO_FN_PTR(gps_t, dlsym(RTLD_DEFAULT, "getpagesizes"));
- if (gps_func == NULL) {
- if (warn) {
- warning("MPSS is not supported by the operating system.");
- }
- return false;
- }
- }
-
- // Fill the array of page sizes.
- int n = (*gps_func)(_page_sizes, page_sizes_max);
- assert(n > 0, "Solaris bug?");
-
- if (n == page_sizes_max) {
- // Add a sentinel value (necessary only if the array was completely filled
- // since it is static (zeroed at initialization)).
- _page_sizes[--n] = 0;
- DEBUG_ONLY(warning("increase the size of the os::_page_sizes array.");)
- }
- assert(_page_sizes[n] == 0, "missing sentinel");
- trace_page_sizes("available page sizes", _page_sizes, n);
-
- if (n == 1) return false; // Only one page size available.
-
- // Skip sizes larger than 4M (or LargePageSizeInBytes if it was set) and
- // select up to usable_count elements. First sort the array, find the first
- // acceptable value, then copy the usable sizes to the top of the array and
- // trim the rest. Make sure to include the default page size :-).
- //
- // A better policy could get rid of the 4M limit by taking the sizes of the
- // important VM memory regions (java heap and possibly the code cache) into
- // account.
- insertion_sort_descending(_page_sizes, n);
- const size_t size_limit =
- FLAG_IS_DEFAULT(LargePageSizeInBytes) ? 4 * M : LargePageSizeInBytes;
- int beg;
- for (beg = 0; beg < n && _page_sizes[beg] > size_limit; ++beg) /* empty */;
- const int end = MIN2((int)usable_count, n) - 1;
- for (int cur = 0; cur < end; ++cur, ++beg) {
- _page_sizes[cur] = _page_sizes[beg];
- }
- _page_sizes[end] = vm_page_size();
- _page_sizes[end + 1] = 0;
-
- if (_page_sizes[end] > _page_sizes[end - 1]) {
- // Default page size is not the smallest; sort again.
- insertion_sort_descending(_page_sizes, end + 1);
- }
- *page_size = _page_sizes[0];
-
- trace_page_sizes("usable page sizes", _page_sizes, end + 1);
- return true;
-}
-
-void os::large_page_init() {
- if (UseLargePages) {
- // print a warning if any large page related flag is specified on command line
- bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
- !FLAG_IS_DEFAULT(LargePageSizeInBytes);
-
- UseLargePages = Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size);
- }
-}
-
-bool os::Solaris::is_valid_page_size(size_t bytes) {
- for (int i = 0; _page_sizes[i] != 0; i++) {
- if (_page_sizes[i] == bytes) {
- return true;
- }
- }
- return false;
-}
-
-bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) {
- assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align);
- assert(is_aligned((void*) start, align),
- PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align);
- assert(is_aligned(bytes, align),
- SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align);
-
- // Signal to OS that we want large pages for addresses
- // from addr, addr + bytes
- struct memcntl_mha mpss_struct;
- mpss_struct.mha_cmd = MHA_MAPSIZE_VA;
- mpss_struct.mha_pagesize = align;
- mpss_struct.mha_flags = 0;
- // Upon successful completion, memcntl() returns 0
- if (memcntl(start, bytes, MC_HAT_ADVISE, (caddr_t) &mpss_struct, 0, 0)) {
- debug_only(warning("Attempt to use MPSS failed."));
- return false;
- }
- return true;
-}
-
-char* os::pd_reserve_memory_special(size_t size, size_t alignment, char* addr, bool exec) {
- fatal("os::reserve_memory_special should not be called on Solaris.");
- return NULL;
-}
-
-bool os::pd_release_memory_special(char* base, size_t bytes) {
- fatal("os::release_memory_special should not be called on Solaris.");
- return false;
-}
-
-size_t os::large_page_size() {
- return _large_page_size;
-}
-
-// MPSS allows application to commit large page memory on demand; with ISM
-// the entire memory region must be allocated as shared memory.
-bool os::can_commit_large_page_memory() {
- return true;
-}
-
-bool os::can_execute_large_page_memory() {
- return true;
-}
-
-// Sleep forever; naked call to OS-specific sleep; use with CAUTION
-void os::infinite_sleep() {
- while (true) { // sleep forever ...
- ::sleep(100); // ... 100 seconds at a time
- }
-}
-
-// Used to convert frequent JVM_Yield() to nops
-bool os::dont_yield() {
- if (DontYieldALot) {
- static hrtime_t last_time = 0;
- hrtime_t diff = getTimeNanos() - last_time;
-
- if (diff < DontYieldALotInterval * 1000000) {
- return true;
- }
-
- last_time += diff;
-
- return false;
- } else {
- return false;
- }
-}
-
-// Note that yield semantics are defined by the scheduling class to which
-// the thread currently belongs. Typically, yield will _not yield to
-// other equal or higher priority threads that reside on the dispatch queues
-// of other CPUs.
-
-void os::naked_yield() {
- thr_yield();
-}
-
-// Interface for setting lwp priorities. We are using T2 libthread,
-// which forces the use of bound threads, so all of our threads will
-// be assigned to real lwp's. Using the thr_setprio function is
-// meaningless in this mode so we must adjust the real lwp's priority.
-// The routines below implement the getting and setting of lwp priorities.
-//
-// Note: There are three priority scales used on Solaris. Java priotities
-// which range from 1 to 10, libthread "thr_setprio" scale which range
-// from 0 to 127, and the current scheduling class of the process we
-// are running in. This is typically from -60 to +60.
-// The setting of the lwp priorities in done after a call to thr_setprio
-// so Java priorities are mapped to libthread priorities and we map from
-// the latter to lwp priorities. We don't keep priorities stored in
-// Java priorities since some of our worker threads want to set priorities
-// higher than all Java threads.
-//
-// For related information:
-// (1) man -s 2 priocntl
-// (2) man -s 4 priocntl
-// (3) man dispadmin
-// = librt.so
-// = libthread/common/rtsched.c - thrp_setlwpprio().
-// = ps -cL ... to validate priority.
-// = sched_get_priority_min and _max
-// pthread_create
-// sched_setparam
-// pthread_setschedparam
-//
-// Assumptions:
-// + We assume that all threads in the process belong to the same
-// scheduling class. IE. an homogenous process.
-// + Must be root or in IA group to change change "interactive" attribute.
-// Priocntl() will fail silently. The only indication of failure is when
-// we read-back the value and notice that it hasn't changed.
-// + Interactive threads enter the runq at the head, non-interactive at the tail.
-// + For RT, change timeslice as well. Invariant:
-// constant "priority integral"
-// Konst == TimeSlice * (60-Priority)
-// Given a priority, compute appropriate timeslice.
-// + Higher numerical values have higher priority.
-
-// sched class attributes
-typedef struct {
- int schedPolicy; // classID
- int maxPrio;
- int minPrio;
-} SchedInfo;
-
-
-static SchedInfo tsLimits, iaLimits, rtLimits, fxLimits;
-
-#ifdef ASSERT
-static int ReadBackValidate = 1;
-#endif
-static int myClass = 0;
-static int myMin = 0;
-static int myMax = 0;
-static int myCur = 0;
-static bool priocntl_enable = false;
-
-static const int criticalPrio = FXCriticalPriority;
-static int java_MaxPriority_to_os_priority = 0; // Saved mapping
-
-
-// lwp_priocntl_init
-//
-// Try to determine the priority scale for our process.
-//
-// Return errno or 0 if OK.
-//
-static int lwp_priocntl_init() {
- int rslt;
- pcinfo_t ClassInfo;
- pcparms_t ParmInfo;
- int i;
-
- if (!UseThreadPriorities) return 0;
-
- // If ThreadPriorityPolicy is 1, switch tables
- if (ThreadPriorityPolicy == 1) {
- for (i = 0; i < CriticalPriority+1; i++)
- os::java_to_os_priority[i] = prio_policy1[i];
- }
- if (UseCriticalJavaThreadPriority) {
- // MaxPriority always maps to the FX scheduling class and criticalPrio.
- // See set_native_priority() and set_lwp_class_and_priority().
- // Save original MaxPriority mapping in case attempt to
- // use critical priority fails.
- java_MaxPriority_to_os_priority = os::java_to_os_priority[MaxPriority];
- // Set negative to distinguish from other priorities
- os::java_to_os_priority[MaxPriority] = -criticalPrio;
- }
-
- // Get IDs for a set of well-known scheduling classes.
- // TODO-FIXME: GETCLINFO returns the current # of classes in the
- // the system. We should have a loop that iterates over the
- // classID values, which are known to be "small" integers.
-
- strcpy(ClassInfo.pc_clname, "TS");
- ClassInfo.pc_cid = -1;
- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
- if (rslt < 0) return errno;
- assert(ClassInfo.pc_cid != -1, "cid for TS class is -1");
- tsLimits.schedPolicy = ClassInfo.pc_cid;
- tsLimits.maxPrio = ((tsinfo_t*)ClassInfo.pc_clinfo)->ts_maxupri;
- tsLimits.minPrio = -tsLimits.maxPrio;
-
- strcpy(ClassInfo.pc_clname, "IA");
- ClassInfo.pc_cid = -1;
- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
- if (rslt < 0) return errno;
- assert(ClassInfo.pc_cid != -1, "cid for IA class is -1");
- iaLimits.schedPolicy = ClassInfo.pc_cid;
- iaLimits.maxPrio = ((iainfo_t*)ClassInfo.pc_clinfo)->ia_maxupri;
- iaLimits.minPrio = -iaLimits.maxPrio;
-
- strcpy(ClassInfo.pc_clname, "RT");
- ClassInfo.pc_cid = -1;
- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
- if (rslt < 0) return errno;
- assert(ClassInfo.pc_cid != -1, "cid for RT class is -1");
- rtLimits.schedPolicy = ClassInfo.pc_cid;
- rtLimits.maxPrio = ((rtinfo_t*)ClassInfo.pc_clinfo)->rt_maxpri;
- rtLimits.minPrio = 0;
-
- strcpy(ClassInfo.pc_clname, "FX");
- ClassInfo.pc_cid = -1;
- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
- if (rslt < 0) return errno;
- assert(ClassInfo.pc_cid != -1, "cid for FX class is -1");
- fxLimits.schedPolicy = ClassInfo.pc_cid;
- fxLimits.maxPrio = ((fxinfo_t*)ClassInfo.pc_clinfo)->fx_maxupri;
- fxLimits.minPrio = 0;
-
- // Query our "current" scheduling class.
- // This will normally be IA, TS or, rarely, FX or RT.
- memset(&ParmInfo, 0, sizeof(ParmInfo));
- ParmInfo.pc_cid = PC_CLNULL;
- rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
- if (rslt < 0) return errno;
- myClass = ParmInfo.pc_cid;
-
- // We now know our scheduling classId, get specific information
- // about the class.
- ClassInfo.pc_cid = myClass;
- ClassInfo.pc_clname[0] = 0;
- rslt = priocntl((idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo);
- if (rslt < 0) return errno;
-
- if (ThreadPriorityVerbose) {
- tty->print_cr("lwp_priocntl_init: Class=%d(%s)...", myClass, ClassInfo.pc_clname);
- }
-
- memset(&ParmInfo, 0, sizeof(pcparms_t));
- ParmInfo.pc_cid = PC_CLNULL;
- rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
- if (rslt < 0) return errno;
-
- if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
- myMin = rtLimits.minPrio;
- myMax = rtLimits.maxPrio;
- } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) {
- iaparms_t *iaInfo = (iaparms_t*)ParmInfo.pc_clparms;
- myMin = iaLimits.minPrio;
- myMax = iaLimits.maxPrio;
- myMax = MIN2(myMax, (int)iaInfo->ia_uprilim); // clamp - restrict
- } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) {
- tsparms_t *tsInfo = (tsparms_t*)ParmInfo.pc_clparms;
- myMin = tsLimits.minPrio;
- myMax = tsLimits.maxPrio;
- myMax = MIN2(myMax, (int)tsInfo->ts_uprilim); // clamp - restrict
- } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) {
- fxparms_t *fxInfo = (fxparms_t*)ParmInfo.pc_clparms;
- myMin = fxLimits.minPrio;
- myMax = fxLimits.maxPrio;
- myMax = MIN2(myMax, (int)fxInfo->fx_uprilim); // clamp - restrict
- } else {
- // No clue - punt
- if (ThreadPriorityVerbose) {
- tty->print_cr("Unknown scheduling class: %s ... \n",
- ClassInfo.pc_clname);
- }
- return EINVAL; // no clue, punt
- }
-
- if (ThreadPriorityVerbose) {
- tty->print_cr("Thread priority Range: [%d..%d]\n", myMin, myMax);
- }
-
- priocntl_enable = true; // Enable changing priorities
- return 0;
-}
-
-#define IAPRI(x) ((iaparms_t *)((x).pc_clparms))
-#define RTPRI(x) ((rtparms_t *)((x).pc_clparms))
-#define TSPRI(x) ((tsparms_t *)((x).pc_clparms))
-#define FXPRI(x) ((fxparms_t *)((x).pc_clparms))
-
-
-// scale_to_lwp_priority
-//
-// Convert from the libthread "thr_setprio" scale to our current
-// lwp scheduling class scale.
-//
-static int scale_to_lwp_priority(int rMin, int rMax, int x) {
- int v;
-
- if (x == 127) return rMax; // avoid round-down
- v = (((x*(rMax-rMin)))/128)+rMin;
- return v;
-}
-
-
-// set_lwp_class_and_priority
-int set_lwp_class_and_priority(int ThreadID, int lwpid,
- int newPrio, int new_class, bool scale) {
- int rslt;
- int Actual, Expected, prv;
- pcparms_t ParmInfo; // for GET-SET
-#ifdef ASSERT
- pcparms_t ReadBack; // for readback
-#endif
-
- // Set priority via PC_GETPARMS, update, PC_SETPARMS
- // Query current values.
- // TODO: accelerate this by eliminating the PC_GETPARMS call.
- // Cache "pcparms_t" in global ParmCache.
- // TODO: elide set-to-same-value
-
- // If something went wrong on init, don't change priorities.
- if (!priocntl_enable) {
- if (ThreadPriorityVerbose) {
- tty->print_cr("Trying to set priority but init failed, ignoring");
- }
- return EINVAL;
- }
-
- // If lwp hasn't started yet, just return
- // the _start routine will call us again.
- if (lwpid <= 0) {
- if (ThreadPriorityVerbose) {
- tty->print_cr("deferring the set_lwp_class_and_priority of thread "
- INTPTR_FORMAT " to %d, lwpid not set",
- ThreadID, newPrio);
- }
- return 0;
- }
-
- if (ThreadPriorityVerbose) {
- tty->print_cr ("set_lwp_class_and_priority("
- INTPTR_FORMAT "@" INTPTR_FORMAT " %d) ",
- ThreadID, lwpid, newPrio);
- }
-
- memset(&ParmInfo, 0, sizeof(pcparms_t));
- ParmInfo.pc_cid = PC_CLNULL;
- rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo);
- if (rslt < 0) return errno;
-
- int cur_class = ParmInfo.pc_cid;
- ParmInfo.pc_cid = (id_t)new_class;
-
- if (new_class == rtLimits.schedPolicy) {
- rtparms_t *rtInfo = (rtparms_t*)ParmInfo.pc_clparms;
- rtInfo->rt_pri = scale ? scale_to_lwp_priority(rtLimits.minPrio,
- rtLimits.maxPrio, newPrio)
- : newPrio;
- rtInfo->rt_tqsecs = RT_NOCHANGE;
- rtInfo->rt_tqnsecs = RT_NOCHANGE;
- if (ThreadPriorityVerbose) {
- tty->print_cr("RT: %d->%d\n", newPrio, rtInfo->rt_pri);
- }
- } else if (new_class == iaLimits.schedPolicy) {
- iaparms_t* iaInfo = (iaparms_t*)ParmInfo.pc_clparms;
- int maxClamped = MIN2(iaLimits.maxPrio,
- cur_class == new_class
- ? (int)iaInfo->ia_uprilim : iaLimits.maxPrio);
- iaInfo->ia_upri = scale ? scale_to_lwp_priority(iaLimits.minPrio,
- maxClamped, newPrio)
- : newPrio;
- iaInfo->ia_uprilim = cur_class == new_class
- ? IA_NOCHANGE : (pri_t)iaLimits.maxPrio;
- iaInfo->ia_mode = IA_NOCHANGE;
- if (ThreadPriorityVerbose) {
- tty->print_cr("IA: [%d...%d] %d->%d\n",
- iaLimits.minPrio, maxClamped, newPrio, iaInfo->ia_upri);
- }
- } else if (new_class == tsLimits.schedPolicy) {
- tsparms_t* tsInfo = (tsparms_t*)ParmInfo.pc_clparms;
- int maxClamped = MIN2(tsLimits.maxPrio,
- cur_class == new_class
- ? (int)tsInfo->ts_uprilim : tsLimits.maxPrio);
- tsInfo->ts_upri = scale ? scale_to_lwp_priority(tsLimits.minPrio,
- maxClamped, newPrio)
- : newPrio;
- tsInfo->ts_uprilim = cur_class == new_class
- ? TS_NOCHANGE : (pri_t)tsLimits.maxPrio;
- if (ThreadPriorityVerbose) {
- tty->print_cr("TS: [%d...%d] %d->%d\n",
- tsLimits.minPrio, maxClamped, newPrio, tsInfo->ts_upri);
- }
- } else if (new_class == fxLimits.schedPolicy) {
- fxparms_t* fxInfo = (fxparms_t*)ParmInfo.pc_clparms;
- int maxClamped = MIN2(fxLimits.maxPrio,
- cur_class == new_class
- ? (int)fxInfo->fx_uprilim : fxLimits.maxPrio);
- fxInfo->fx_upri = scale ? scale_to_lwp_priority(fxLimits.minPrio,
- maxClamped, newPrio)
- : newPrio;
- fxInfo->fx_uprilim = cur_class == new_class
- ? FX_NOCHANGE : (pri_t)fxLimits.maxPrio;
- fxInfo->fx_tqsecs = FX_NOCHANGE;
- fxInfo->fx_tqnsecs = FX_NOCHANGE;
- if (ThreadPriorityVerbose) {
- tty->print_cr("FX: [%d...%d] %d->%d\n",
- fxLimits.minPrio, maxClamped, newPrio, fxInfo->fx_upri);
- }
- } else {
- if (ThreadPriorityVerbose) {
- tty->print_cr("Unknown new scheduling class %d\n", new_class);
- }
- return EINVAL; // no clue, punt
- }
-
- rslt = priocntl(P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo);
- if (ThreadPriorityVerbose && rslt) {
- tty->print_cr ("PC_SETPARMS ->%d %d\n", rslt, errno);
- }
- if (rslt < 0) return errno;
-
-#ifdef ASSERT
- // Sanity check: read back what we just attempted to set.
- // In theory it could have changed in the interim ...
- //
- // The priocntl system call is tricky.
- // Sometimes it'll validate the priority value argument and
- // return EINVAL if unhappy. At other times it fails silently.
- // Readbacks are prudent.
-
- if (!ReadBackValidate) return 0;
-
- memset(&ReadBack, 0, sizeof(pcparms_t));
- ReadBack.pc_cid = PC_CLNULL;
- rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack);
- assert(rslt >= 0, "priocntl failed");
- Actual = Expected = 0xBAD;
- assert(ParmInfo.pc_cid == ReadBack.pc_cid, "cid's don't match");
- if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
- Actual = RTPRI(ReadBack)->rt_pri;
- Expected = RTPRI(ParmInfo)->rt_pri;
- } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) {
- Actual = IAPRI(ReadBack)->ia_upri;
- Expected = IAPRI(ParmInfo)->ia_upri;
- } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) {
- Actual = TSPRI(ReadBack)->ts_upri;
- Expected = TSPRI(ParmInfo)->ts_upri;
- } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) {
- Actual = FXPRI(ReadBack)->fx_upri;
- Expected = FXPRI(ParmInfo)->fx_upri;
- } else {
- if (ThreadPriorityVerbose) {
- tty->print_cr("set_lwp_class_and_priority: unexpected class in readback: %d\n",
- ParmInfo.pc_cid);
- }
- }
-
- if (Actual != Expected) {
- if (ThreadPriorityVerbose) {
- tty->print_cr ("set_lwp_class_and_priority(%d %d) Class=%d: actual=%d vs expected=%d\n",
- lwpid, newPrio, ReadBack.pc_cid, Actual, Expected);
- }
- }
-#endif
-
- return 0;
-}
-
-// Solaris only gives access to 128 real priorities at a time,
-// so we expand Java's ten to fill this range. This would be better
-// if we dynamically adjusted relative priorities.
-//
-// The ThreadPriorityPolicy option allows us to select 2 different
-// priority scales.
-//
-// ThreadPriorityPolicy=0
-// Since the Solaris' default priority is MaximumPriority, we do not
-// set a priority lower than Max unless a priority lower than
-// NormPriority is requested.
-//
-// ThreadPriorityPolicy=1
-// This mode causes the priority table to get filled with
-// linear values. NormPriority get's mapped to 50% of the
-// Maximum priority an so on. This will cause VM threads
-// to get unfair treatment against other Solaris processes
-// which do not explicitly alter their thread priorities.
-
-int os::java_to_os_priority[CriticalPriority + 1] = {
- -99999, // 0 Entry should never be used
-
- 0, // 1 MinPriority
- 32, // 2
- 64, // 3
-
- 96, // 4
- 127, // 5 NormPriority
- 127, // 6
-
- 127, // 7
- 127, // 8
- 127, // 9 NearMaxPriority
-
- 127, // 10 MaxPriority
-
- -criticalPrio // 11 CriticalPriority
-};
-
-OSReturn os::set_native_priority(Thread* thread, int newpri) {
- OSThread* osthread = thread->osthread();
-
- // Save requested priority in case the thread hasn't been started
- osthread->set_native_priority(newpri);
-
- // Check for critical priority request
- bool fxcritical = false;
- if (newpri == -criticalPrio) {
- fxcritical = true;
- newpri = criticalPrio;
- }
-
- assert(newpri >= MinimumPriority && newpri <= MaximumPriority, "bad priority mapping");
- if (!UseThreadPriorities) return OS_OK;
-
- int status = 0;
-
- if (!fxcritical) {
- // Use thr_setprio only if we have a priority that thr_setprio understands
- status = thr_setprio(thread->osthread()->thread_id(), newpri);
- }
-
- int lwp_status =
- set_lwp_class_and_priority(osthread->thread_id(),
- osthread->lwp_id(),
- newpri,
- fxcritical ? fxLimits.schedPolicy : myClass,
- !fxcritical);
- if (lwp_status != 0 && fxcritical) {
- // Try again, this time without changing the scheduling class
- newpri = java_MaxPriority_to_os_priority;
- lwp_status = set_lwp_class_and_priority(osthread->thread_id(),
- osthread->lwp_id(),
- newpri, myClass, false);
- }
- status |= lwp_status;
- return (status == 0) ? OS_OK : OS_ERR;
-}
-
-
-OSReturn os::get_native_priority(const Thread* const thread,
- int *priority_ptr) {
- int p;
- if (!UseThreadPriorities) {
- *priority_ptr = NormalPriority;
- return OS_OK;
- }
- int status = thr_getprio(thread->osthread()->thread_id(), &p);
- if (status != 0) {
- return OS_ERR;
- }
- *priority_ptr = p;
- return OS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// suspend/resume support
-
-// The low-level signal-based suspend/resume support is a remnant from the
-// old VM-suspension that used to be for java-suspension, safepoints etc,
-// within hotspot. Currently used by JFR's OSThreadSampler
-//
-// The remaining code is greatly simplified from the more general suspension
-// code that used to be used.
-//
-// The protocol is quite simple:
-// - suspend:
-// - sends a signal to the target thread
-// - polls the suspend state of the osthread using a yield loop
-// - target thread signal handler (SR_handler) sets suspend state
-// and blocks in sigsuspend until continued
-// - resume:
-// - sets target osthread state to continue
-// - sends signal to end the sigsuspend loop in the SR_handler
-//
-// Note that the SR_lock plays no role in this suspend/resume protocol,
-// but is checked for NULL in SR_handler as a thread termination indicator.
-// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
-//
-// Note that resume_clear_context() and suspend_save_context() are needed
-// by SR_handler(), so that fetch_frame_from_ucontext() works,
-// which in part is used by:
-// - Forte Analyzer: AsyncGetCallTrace()
-// - StackBanging: get_frame_at_stack_banging_point()
-// - JFR: get_topframe()-->....-->get_valid_uc_in_signal_handler()
-
-static void resume_clear_context(OSThread *osthread) {
- osthread->set_ucontext(NULL);
-}
-
-static void suspend_save_context(OSThread *osthread, ucontext_t* context) {
- osthread->set_ucontext(context);
-}
-
-static PosixSemaphore sr_semaphore;
-
-void os::Solaris::SR_handler(Thread* thread, ucontext_t* context) {
- // Save and restore errno to avoid confusing native code with EINTR
- // after sigsuspend.
- int old_errno = errno;
-
- OSThread* osthread = thread->osthread();
- assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread");
-
- os::SuspendResume::State current = osthread->sr.state();
- if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
- suspend_save_context(osthread, context);
-
- // attempt to switch the state, we assume we had a SUSPEND_REQUEST
- os::SuspendResume::State state = osthread->sr.suspended();
- if (state == os::SuspendResume::SR_SUSPENDED) {
- sigset_t suspend_set; // signals for sigsuspend()
-
- // get current set of blocked signals and unblock resume signal
- pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
- sigdelset(&suspend_set, ASYNC_SIGNAL);
-
- sr_semaphore.signal();
- // wait here until we are resumed
- while (1) {
- sigsuspend(&suspend_set);
-
- os::SuspendResume::State result = osthread->sr.running();
- if (result == os::SuspendResume::SR_RUNNING) {
- sr_semaphore.signal();
- break;
- }
- }
-
- } else if (state == os::SuspendResume::SR_RUNNING) {
- // request was cancelled, continue
- } else {
- ShouldNotReachHere();
- }
-
- resume_clear_context(osthread);
- } else if (current == os::SuspendResume::SR_RUNNING) {
- // request was cancelled, continue
- } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) {
- // ignore
- } else {
- // ignore
- }
-
- errno = old_errno;
-}
-
-void os::print_statistics() {
-}
-
-bool os::message_box(const char* title, const char* message) {
- int i;
- fdStream err(defaultStream::error_fd());
- for (i = 0; i < 78; i++) err.print_raw("=");
- err.cr();
- err.print_raw_cr(title);
- for (i = 0; i < 78; i++) err.print_raw("-");
- err.cr();
- err.print_raw_cr(message);
- for (i = 0; i < 78; i++) err.print_raw("=");
- err.cr();
-
- char buf[16];
- // Prevent process from exiting upon "read error" without consuming all CPU
- while (::read(0, buf, sizeof(buf)) <= 0) { ::sleep(100); }
-
- return buf[0] == 'y' || buf[0] == 'Y';
-}
-
-static int sr_notify(OSThread* osthread) {
- int status = thr_kill(osthread->thread_id(), ASYNC_SIGNAL);
- assert_status(status == 0, status, "thr_kill");
- return status;
-}
-
-// "Randomly" selected value for how long we want to spin
-// before bailing out on suspending a thread, also how often
-// we send a signal to a thread we want to resume
-static const int RANDOMLY_LARGE_INTEGER = 1000000;
-static const int RANDOMLY_LARGE_INTEGER2 = 100;
-
-static bool do_suspend(OSThread* osthread) {
- assert(osthread->sr.is_running(), "thread should be running");
- assert(!sr_semaphore.trywait(), "semaphore has invalid state");
-
- // mark as suspended and send signal
- if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) {
- // failed to switch, state wasn't running?
- ShouldNotReachHere();
- return false;
- }
-
- if (sr_notify(osthread) != 0) {
- ShouldNotReachHere();
- }
-
- // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
- while (true) {
- if (sr_semaphore.timedwait(2000)) {
- break;
- } else {
- // timeout
- os::SuspendResume::State cancelled = osthread->sr.cancel_suspend();
- if (cancelled == os::SuspendResume::SR_RUNNING) {
- return false;
- } else if (cancelled == os::SuspendResume::SR_SUSPENDED) {
- // make sure that we consume the signal on the semaphore as well
- sr_semaphore.wait();
- break;
- } else {
- ShouldNotReachHere();
- return false;
- }
- }
- }
-
- guarantee(osthread->sr.is_suspended(), "Must be suspended");
- return true;
-}
-
-static void do_resume(OSThread* osthread) {
- assert(osthread->sr.is_suspended(), "thread should be suspended");
- assert(!sr_semaphore.trywait(), "invalid semaphore state");
-
- if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) {
- // failed to switch to WAKEUP_REQUEST
- ShouldNotReachHere();
- return;
- }
-
- while (true) {
- if (sr_notify(osthread) == 0) {
- if (sr_semaphore.timedwait(2)) {
- if (osthread->sr.is_running()) {
- return;
- }
- }
- } else {
- ShouldNotReachHere();
- }
- }
-
- guarantee(osthread->sr.is_running(), "Must be running!");
-}
-
-void os::SuspendedThreadTask::internal_do_task() {
- if (do_suspend(_thread->osthread())) {
- SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext());
- do_task(context);
- do_resume(_thread->osthread());
- }
-}
-
-// This does not do anything on Solaris. This is basically a hook for being
-// able to use structured exception handling (thread-local exception filters) on, e.g., Win32.
-void os::os_exception_wrapper(java_call_t f, JavaValue* value,
- const methodHandle& method, JavaCallArguments* args,
- Thread* thread) {
- f(value, method, args, thread);
-}
-
-// This routine may be used by user applications as a "hook" to catch signals.
-// The user-defined signal handler must pass unrecognized signals to this
-// routine, and if it returns true (non-zero), then the signal handler must
-// return immediately. If the flag "abort_if_unrecognized" is true, then this
-// routine will never retun false (zero), but instead will execute a VM panic
-// routine kill the process.
-//
-// If this routine returns false, it is OK to call it again. This allows
-// the user-defined signal handler to perform checks either before or after
-// the VM performs its own checks. Naturally, the user code would be making
-// a serious error if it tried to handle an exception (such as a null check
-// or breakpoint) that the VM was generating for its own correct operation.
-//
-// This routine may recognize any of the following kinds of signals:
-// SIGBUS, SIGSEGV, SIGILL, SIGFPE, BREAK_SIGNAL, SIGPIPE, SIGXFSZ,
-// ASYNC_SIGNAL.
-// It should be consulted by handlers for any of those signals.
-//
-// The caller of this routine must pass in the three arguments supplied
-// to the function referred to in the "sa_sigaction" (not the "sa_handler")
-// field of the structure passed to sigaction(). This routine assumes that
-// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART.
-//
-// Note that the VM will print warnings if it detects conflicting signal
-// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers".
-//
-extern "C" JNIEXPORT int JVM_handle_solaris_signal(int signo,
- siginfo_t* siginfo,
- void* ucontext,
- int abort_if_unrecognized);
-
-
-void signalHandler(int sig, siginfo_t* info, void* ucVoid) {
- int orig_errno = errno; // Preserve errno value over signal handler.
- JVM_handle_solaris_signal(sig, info, ucVoid, true);
- errno = orig_errno;
-}
-
-// This boolean allows users to forward their own non-matching signals
-// to JVM_handle_solaris_signal, harmlessly.
-bool os::Solaris::signal_handlers_are_installed = false;
-
-// For signal-chaining
-bool os::Solaris::libjsig_is_loaded = false;
-typedef struct sigaction *(*get_signal_t)(int);
-get_signal_t os::Solaris::get_signal_action = NULL;
-
-struct sigaction* os::Solaris::get_chained_signal_action(int sig) {
- struct sigaction *actp = NULL;
-
- if ((libjsig_is_loaded) && (sig <= Maxsignum)) {
- // Retrieve the old signal handler from libjsig
- actp = (*get_signal_action)(sig);
- }
- if (actp == NULL) {
- // Retrieve the preinstalled signal handler from jvm
- actp = get_preinstalled_handler(sig);
- }
-
- return actp;
-}
-
-static bool call_chained_handler(struct sigaction *actp, int sig,
- siginfo_t *siginfo, void *context) {
- // Call the old signal handler
- if (actp->sa_handler == SIG_DFL) {
- // It's more reasonable to let jvm treat it as an unexpected exception
- // instead of taking the default action.
- return false;
- } else if (actp->sa_handler != SIG_IGN) {
- if ((actp->sa_flags & SA_NODEFER) == 0) {
- // automaticlly block the signal
- sigaddset(&(actp->sa_mask), sig);
- }
-
- sa_handler_t hand;
- sa_sigaction_t sa;
- bool siginfo_flag_set = (actp->sa_flags & SA_SIGINFO) != 0;
- // retrieve the chained handler
- if (siginfo_flag_set) {
- sa = actp->sa_sigaction;
- } else {
- hand = actp->sa_handler;
- }
-
- if ((actp->sa_flags & SA_RESETHAND) != 0) {
- actp->sa_handler = SIG_DFL;
- }
-
- // try to honor the signal mask
- sigset_t oset;
- pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset);
-
- // call into the chained handler
- if (siginfo_flag_set) {
- (*sa)(sig, siginfo, context);
- } else {
- (*hand)(sig);
- }
-
- // restore the signal mask
- pthread_sigmask(SIG_SETMASK, &oset, 0);
- }
- // Tell jvm's signal handler the signal is taken care of.
- return true;
-}
-
-bool os::Solaris::chained_handler(int sig, siginfo_t* siginfo, void* context) {
- bool chained = false;
- // signal-chaining
- if (UseSignalChaining) {
- struct sigaction *actp = get_chained_signal_action(sig);
- if (actp != NULL) {
- chained = call_chained_handler(actp, sig, siginfo, context);
- }
- }
- return chained;
-}
-
-struct sigaction* os::Solaris::get_preinstalled_handler(int sig) {
- assert((chainedsigactions != (struct sigaction *)NULL) &&
- (preinstalled_sigs != (int *)NULL), "signals not yet initialized");
- if (preinstalled_sigs[sig] != 0) {
- return &chainedsigactions[sig];
- }
- return NULL;
-}
-
-void os::Solaris::save_preinstalled_handler(int sig,
- struct sigaction& oldAct) {
- assert(sig > 0 && sig <= Maxsignum, "vm signal out of expected range");
- assert((chainedsigactions != (struct sigaction *)NULL) &&
- (preinstalled_sigs != (int *)NULL), "signals not yet initialized");
- chainedsigactions[sig] = oldAct;
- preinstalled_sigs[sig] = 1;
-}
-
-void os::Solaris::set_signal_handler(int sig, bool set_installed,
- bool oktochain) {
- // Check for overwrite.
- struct sigaction oldAct;
- sigaction(sig, (struct sigaction*)NULL, &oldAct);
- void* oldhand =
- oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
- : CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
- if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) &&
- oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) &&
- oldhand != CAST_FROM_FN_PTR(void*, signalHandler)) {
- if (AllowUserSignalHandlers || !set_installed) {
- // Do not overwrite; user takes responsibility to forward to us.
- return;
- } else if (UseSignalChaining) {
- if (oktochain) {
- // save the old handler in jvm
- save_preinstalled_handler(sig, oldAct);
- } else {
- vm_exit_during_initialization("Signal chaining not allowed for VM interrupt signal.");
- }
- // libjsig also interposes the sigaction() call below and saves the
- // old sigaction on it own.
- } else {
- fatal("Encountered unexpected pre-existing sigaction handler "
- "%#lx for signal %d.", (long)oldhand, sig);
- }
- }
-
- struct sigaction sigAct;
- sigfillset(&(sigAct.sa_mask));
- sigAct.sa_handler = SIG_DFL;
-
- sigAct.sa_sigaction = signalHandler;
- // Handle SIGSEGV on alternate signal stack if
- // not using stack banging
- if (!UseStackBanging && sig == SIGSEGV) {
- sigAct.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
- } else {
- sigAct.sa_flags = SA_SIGINFO | SA_RESTART;
- }
- os::Solaris::set_our_sigflags(sig, sigAct.sa_flags);
-
- sigaction(sig, &sigAct, &oldAct);
-
- void* oldhand2 = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
- : CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
- assert(oldhand2 == oldhand, "no concurrent signal handler installation");
-}
-
-
-#define DO_SIGNAL_CHECK(sig) \
- do { \
- if (!sigismember(&check_signal_done, sig)) { \
- os::Solaris::check_signal_handler(sig); \
- } \
- } while (0)
-
-// This method is a periodic task to check for misbehaving JNI applications
-// under CheckJNI, we can add any periodic checks here
-
-void os::run_periodic_checks() {
- // A big source of grief is hijacking virt. addr 0x0 on Solaris,
- // thereby preventing a NULL checks.
- if (!check_addr0_done) check_addr0_done = check_addr0(tty);
-
- if (check_signals == false) return;
-
- // SEGV and BUS if overridden could potentially prevent
- // generation of hs*.log in the event of a crash, debugging
- // such a case can be very challenging, so we absolutely
- // check for the following for a good measure:
- DO_SIGNAL_CHECK(SIGSEGV);
- DO_SIGNAL_CHECK(SIGILL);
- DO_SIGNAL_CHECK(SIGFPE);
- DO_SIGNAL_CHECK(SIGBUS);
- DO_SIGNAL_CHECK(SIGPIPE);
- DO_SIGNAL_CHECK(SIGXFSZ);
- DO_SIGNAL_CHECK(ASYNC_SIGNAL);
-
- // ReduceSignalUsage allows the user to override these handlers
- // see comments at the very top and jvm_solaris.h
- if (!ReduceSignalUsage) {
- DO_SIGNAL_CHECK(SHUTDOWN1_SIGNAL);
- DO_SIGNAL_CHECK(SHUTDOWN2_SIGNAL);
- DO_SIGNAL_CHECK(SHUTDOWN3_SIGNAL);
- DO_SIGNAL_CHECK(BREAK_SIGNAL);
- }
-}
-
-typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *);
-
-static os_sigaction_t os_sigaction = NULL;
-
-void os::Solaris::check_signal_handler(int sig) {
- char buf[O_BUFLEN];
- address jvmHandler = NULL;
-
- struct sigaction act;
- if (os_sigaction == NULL) {
- // only trust the default sigaction, in case it has been interposed
- os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction");
- if (os_sigaction == NULL) return;
- }
-
- os_sigaction(sig, (struct sigaction*)NULL, &act);
-
- address thisHandler = (act.sa_flags & SA_SIGINFO)
- ? CAST_FROM_FN_PTR(address, act.sa_sigaction)
- : CAST_FROM_FN_PTR(address, act.sa_handler);
-
-
- switch (sig) {
- case SIGSEGV:
- case SIGBUS:
- case SIGFPE:
- case SIGPIPE:
- case SIGXFSZ:
- case SIGILL:
- case ASYNC_SIGNAL:
- jvmHandler = CAST_FROM_FN_PTR(address, signalHandler);
- break;
-
- case SHUTDOWN1_SIGNAL:
- case SHUTDOWN2_SIGNAL:
- case SHUTDOWN3_SIGNAL:
- case BREAK_SIGNAL:
- jvmHandler = (address)user_handler();
- break;
-
- default:
- return;
- }
-
- if (thisHandler != jvmHandler) {
- tty->print("Warning: %s handler ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:%s", get_signal_handler_name(jvmHandler, buf, O_BUFLEN));
- tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN));
- // No need to check this sig any longer
- sigaddset(&check_signal_done, sig);
- // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN
- if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) {
- tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell",
- exception_name(sig, buf, O_BUFLEN));
- }
- } else if(os::Solaris::get_our_sigflags(sig) != 0 && act.sa_flags != os::Solaris::get_our_sigflags(sig)) {
- tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:");
- os::Posix::print_sa_flags(tty, os::Solaris::get_our_sigflags(sig));
- tty->cr();
- tty->print(" found:");
- os::Posix::print_sa_flags(tty, act.sa_flags);
- tty->cr();
- // No need to check this sig any longer
- sigaddset(&check_signal_done, sig);
- }
-
- // Print all the signal handler state
- if (sigismember(&check_signal_done, sig)) {
- print_signal_handlers(tty, buf, O_BUFLEN);
- }
-
-}
-
-void os::Solaris::install_signal_handlers() {
- signal_handlers_are_installed = true;
-
- // signal-chaining
- typedef void (*signal_setting_t)();
- signal_setting_t begin_signal_setting = NULL;
- signal_setting_t end_signal_setting = NULL;
- begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
- dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting"));
- if (begin_signal_setting != NULL) {
- end_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
- dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
- get_signal_action = CAST_TO_FN_PTR(get_signal_t,
- dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
- libjsig_is_loaded = true;
- assert(UseSignalChaining, "should enable signal-chaining");
- }
- if (libjsig_is_loaded) {
- // Tell libjsig jvm is setting signal handlers
- (*begin_signal_setting)();
- }
-
- set_signal_handler(SIGSEGV, true, true);
- set_signal_handler(SIGPIPE, true, true);
- set_signal_handler(SIGXFSZ, true, true);
- set_signal_handler(SIGBUS, true, true);
- set_signal_handler(SIGILL, true, true);
- set_signal_handler(SIGFPE, true, true);
- set_signal_handler(ASYNC_SIGNAL, true, true);
-
- if (libjsig_is_loaded) {
- // Tell libjsig jvm finishes setting signal handlers
- (*end_signal_setting)();
- }
-
- // We don't activate signal checker if libjsig is in place, we trust ourselves
- // and if UserSignalHandler is installed all bets are off.
- // Log that signal checking is off only if -verbose:jni is specified.
- if (CheckJNICalls) {
- if (libjsig_is_loaded) {
- log_debug(jni, resolve)("Info: libjsig is activated, all active signal checking is disabled");
- check_signals = false;
- }
- if (AllowUserSignalHandlers) {
- log_debug(jni, resolve)("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
- check_signals = false;
- }
- }
-}
-
-
-void report_error(const char* file_name, int line_no, const char* title,
- const char* format, ...);
-
-// (Static) wrappers for the liblgrp API
-os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home;
-os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init;
-os::Solaris::lgrp_fini_func_t os::Solaris::_lgrp_fini;
-os::Solaris::lgrp_root_func_t os::Solaris::_lgrp_root;
-os::Solaris::lgrp_children_func_t os::Solaris::_lgrp_children;
-os::Solaris::lgrp_resources_func_t os::Solaris::_lgrp_resources;
-os::Solaris::lgrp_nlgrps_func_t os::Solaris::_lgrp_nlgrps;
-os::Solaris::lgrp_cookie_stale_func_t os::Solaris::_lgrp_cookie_stale;
-os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0;
-
-static address resolve_symbol_lazy(const char* name) {
- address addr = (address) dlsym(RTLD_DEFAULT, name);
- if (addr == NULL) {
- // RTLD_DEFAULT was not defined on some early versions of 2.5.1
- addr = (address) dlsym(RTLD_NEXT, name);
- }
- return addr;
-}
-
-static address resolve_symbol(const char* name) {
- address addr = resolve_symbol_lazy(name);
- if (addr == NULL) {
- fatal(dlerror());
- }
- return addr;
-}
-
-void os::Solaris::libthread_init() {
- address func = (address)dlsym(RTLD_DEFAULT, "_thr_suspend_allmutators");
-
- lwp_priocntl_init();
-
- // RTLD_DEFAULT was not defined on some early versions of 5.5.1
- if (func == NULL) {
- func = (address) dlsym(RTLD_NEXT, "_thr_suspend_allmutators");
- // Guarantee that this VM is running on an new enough OS (5.6 or
- // later) that it will have a new enough libthread.so.
- guarantee(func != NULL, "libthread.so is too old.");
- }
-
- int size;
- void (*handler_info_func)(address *, int *);
- handler_info_func = CAST_TO_FN_PTR(void (*)(address *, int *), resolve_symbol("thr_sighndlrinfo"));
- handler_info_func(&handler_start, &size);
- handler_end = handler_start + size;
-}
-
-
-int_fnP_mutex_tP os::Solaris::_mutex_lock;
-int_fnP_mutex_tP os::Solaris::_mutex_trylock;
-int_fnP_mutex_tP os::Solaris::_mutex_unlock;
-int_fnP_mutex_tP_i_vP os::Solaris::_mutex_init;
-int_fnP_mutex_tP os::Solaris::_mutex_destroy;
-int os::Solaris::_mutex_scope = USYNC_THREAD;
-
-int_fnP_cond_tP_mutex_tP_timestruc_tP os::Solaris::_cond_timedwait;
-int_fnP_cond_tP_mutex_tP os::Solaris::_cond_wait;
-int_fnP_cond_tP os::Solaris::_cond_signal;
-int_fnP_cond_tP os::Solaris::_cond_broadcast;
-int_fnP_cond_tP_i_vP os::Solaris::_cond_init;
-int_fnP_cond_tP os::Solaris::_cond_destroy;
-int os::Solaris::_cond_scope = USYNC_THREAD;
-bool os::Solaris::_synchronization_initialized;
-
-void os::Solaris::synchronization_init() {
- if (UseLWPSynchronization) {
- os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_lock")));
- os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_trylock")));
- os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_unlock")));
- os::Solaris::set_mutex_init(lwp_mutex_init);
- os::Solaris::set_mutex_destroy(lwp_mutex_destroy);
- os::Solaris::set_mutex_scope(USYNC_THREAD);
-
- os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("_lwp_cond_timedwait")));
- os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("_lwp_cond_wait")));
- os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("_lwp_cond_signal")));
- os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("_lwp_cond_broadcast")));
- os::Solaris::set_cond_init(lwp_cond_init);
- os::Solaris::set_cond_destroy(lwp_cond_destroy);
- os::Solaris::set_cond_scope(USYNC_THREAD);
- } else {
- os::Solaris::set_mutex_scope(USYNC_THREAD);
- os::Solaris::set_cond_scope(USYNC_THREAD);
-
- if (UsePthreads) {
- os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_lock")));
- os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_trylock")));
- os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_unlock")));
- os::Solaris::set_mutex_init(pthread_mutex_default_init);
- os::Solaris::set_mutex_destroy(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_destroy")));
-
- os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("pthread_cond_timedwait")));
- os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("pthread_cond_wait")));
- os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_signal")));
- os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_broadcast")));
- os::Solaris::set_cond_init(pthread_cond_default_init);
- os::Solaris::set_cond_destroy(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_destroy")));
- } else {
- os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_lock")));
- os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_trylock")));
- os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_unlock")));
- os::Solaris::set_mutex_init(::mutex_init);
- os::Solaris::set_mutex_destroy(::mutex_destroy);
-
- os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("cond_timedwait")));
- os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("cond_wait")));
- os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("cond_signal")));
- os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("cond_broadcast")));
- os::Solaris::set_cond_init(::cond_init);
- os::Solaris::set_cond_destroy(::cond_destroy);
- }
- }
- _synchronization_initialized = true;
-}
-
-bool os::Solaris::liblgrp_init() {
- void *handle = dlopen("liblgrp.so.1", RTLD_LAZY);
- if (handle != NULL) {
- os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home")));
- os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init")));
- os::Solaris::set_lgrp_fini(CAST_TO_FN_PTR(lgrp_fini_func_t, dlsym(handle, "lgrp_fini")));
- os::Solaris::set_lgrp_root(CAST_TO_FN_PTR(lgrp_root_func_t, dlsym(handle, "lgrp_root")));
- os::Solaris::set_lgrp_children(CAST_TO_FN_PTR(lgrp_children_func_t, dlsym(handle, "lgrp_children")));
- os::Solaris::set_lgrp_resources(CAST_TO_FN_PTR(lgrp_resources_func_t, dlsym(handle, "lgrp_resources")));
- os::Solaris::set_lgrp_nlgrps(CAST_TO_FN_PTR(lgrp_nlgrps_func_t, dlsym(handle, "lgrp_nlgrps")));
- os::Solaris::set_lgrp_cookie_stale(CAST_TO_FN_PTR(lgrp_cookie_stale_func_t,
- dlsym(handle, "lgrp_cookie_stale")));
-
- lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER);
- set_lgrp_cookie(c);
- return true;
- }
- return false;
-}
-
-// int pset_getloadavg(psetid_t pset, double loadavg[], int nelem);
-typedef long (*pset_getloadavg_type)(psetid_t pset, double loadavg[], int nelem);
-static pset_getloadavg_type pset_getloadavg_ptr = NULL;
-
-void init_pset_getloadavg_ptr(void) {
- pset_getloadavg_ptr =
- (pset_getloadavg_type)dlsym(RTLD_DEFAULT, "pset_getloadavg");
- if (pset_getloadavg_ptr == NULL) {
- log_warning(os)("pset_getloadavg function not found");
- }
-}
-
-int os::Solaris::_dev_zero_fd = -1;
-
-// this is called _before_ the global arguments have been parsed
-void os::init(void) {
- _initial_pid = getpid();
-
- max_hrtime = first_hrtime = gethrtime();
-
- init_random(1234567);
-
- page_size = sysconf(_SC_PAGESIZE);
- if (page_size == -1) {
- fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno));
- }
- init_page_sizes((size_t) page_size);
-
- Solaris::initialize_system_info();
-
- int fd = ::open("/dev/zero", O_RDWR);
- if (fd < 0) {
- fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno));
- } else {
- Solaris::set_dev_zero_fd(fd);
-
- // Close on exec, child won't inherit.
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- }
-
- clock_tics_per_sec = CLK_TCK;
-
- // check if dladdr1() exists; dladdr1 can provide more information than
- // dladdr for os::dll_address_to_function_name. It comes with SunOS 5.9
- // and is available on linker patches for 5.7 and 5.8.
- // libdl.so must have been loaded, this call is just an entry lookup
- void * hdl = dlopen("libdl.so", RTLD_NOW);
- if (hdl) {
- dladdr1_func = CAST_TO_FN_PTR(dladdr1_func_type, dlsym(hdl, "dladdr1"));
- }
-
- // main_thread points to the thread that created/loaded the JVM.
- main_thread = thr_self();
-
- // dynamic lookup of functions that may not be available in our lowest
- // supported Solaris release
- void * handle = dlopen("libc.so.1", RTLD_LAZY);
- if (handle != NULL) {
- Solaris::_pthread_setname_np = // from 11.3
- (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np");
- }
-
- // Shared Posix initialization
- os::Posix::init();
-}
-
-// To install functions for atexit system call
-extern "C" {
- static void perfMemory_exit_helper() {
- perfMemory_exit();
- }
-}
-
-// this is called _after_ the global arguments have been parsed
-jint os::init_2(void) {
- // try to enable extended file IO ASAP, see 6431278
- os::Solaris::try_enable_extended_io();
-
- // Check and sets minimum stack sizes against command line options
- if (Posix::set_minimum_stack_sizes() == JNI_ERR) {
- return JNI_ERR;
- }
-
- Solaris::libthread_init();
-
- if (UseNUMA) {
- if (!Solaris::liblgrp_init()) {
- FLAG_SET_ERGO(UseNUMA, false);
- } else {
- size_t lgrp_limit = os::numa_get_groups_num();
- int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit, mtInternal);
- size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit);
- FREE_C_HEAP_ARRAY(int, lgrp_ids);
- if (lgrp_num < 2) {
- // There's only one locality group, disable NUMA unless
- // user explicilty forces NUMA optimizations on single-node/UMA systems
- UseNUMA = ForceNUMA;
- }
- }
- }
-
- // When NUMA requested, not-NUMA-aware allocations default to interleaving.
- if (UseNUMA && !UseNUMAInterleaving) {
- FLAG_SET_ERGO_IF_DEFAULT(UseNUMAInterleaving, true);
- }
-
- Solaris::signal_sets_init();
- Solaris::init_signal_mem();
- Solaris::install_signal_handlers();
- // Initialize data for jdk.internal.misc.Signal
- if (!ReduceSignalUsage) {
- jdk_misc_signal_init();
- }
-
- // initialize synchronization primitives to use either thread or
- // lwp synchronization (controlled by UseLWPSynchronization)
- Solaris::synchronization_init();
- DEBUG_ONLY(os::set_mutex_init_done();)
-
- if (MaxFDLimit) {
- // set the number of file descriptors to max. print out error
- // if getrlimit/setrlimit fails but continue regardless.
- struct rlimit nbr_files;
- int status = getrlimit(RLIMIT_NOFILE, &nbr_files);
- if (status != 0) {
- log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno));
- } else {
- nbr_files.rlim_cur = nbr_files.rlim_max;
- status = setrlimit(RLIMIT_NOFILE, &nbr_files);
- if (status != 0) {
- log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno));
- }
- }
- }
-
- // Calculate theoretical max. size of Threads to guard gainst
- // artifical out-of-memory situations, where all available address-
- // space has been reserved by thread stacks. Default stack size is 1Mb.
- size_t pre_thread_stack_size = (JavaThread::stack_size_at_create()) ?
- JavaThread::stack_size_at_create() : (1*K*K);
- assert(pre_thread_stack_size != 0, "Must have a stack");
- // Solaris has a maximum of 4Gb of user programs. Calculate the thread limit when
- // we should start doing Virtual Memory banging. Currently when the threads will
- // have used all but 200Mb of space.
- size_t max_address_space = ((unsigned int)4 * K * K * K) - (200 * K * K);
- Solaris::_os_thread_limit = max_address_space / pre_thread_stack_size;
-
- // at-exit methods are called in the reverse order of their registration.
- // In Solaris 7 and earlier, atexit functions are called on return from
- // main or as a result of a call to exit(3C). There can be only 32 of
- // these functions registered and atexit() does not set errno. In Solaris
- // 8 and later, there is no limit to the number of functions registered
- // and atexit() sets errno. In addition, in Solaris 8 and later, atexit
- // functions are called upon dlclose(3DL) in addition to return from main
- // and exit(3C).
-
- if (PerfAllowAtExitRegistration) {
- // only register atexit functions if PerfAllowAtExitRegistration is set.
- // atexit functions can be delayed until process exit time, which
- // can be problematic for embedded VM situations. Embedded VMs should
- // call DestroyJavaVM() to assure that VM resources are released.
-
- // note: perfMemory_exit_helper atexit function may be removed in
- // the future if the appropriate cleanup code can be added to the
- // VM_Exit VMOperation's doit method.
- if (atexit(perfMemory_exit_helper) != 0) {
- warning("os::init2 atexit(perfMemory_exit_helper) failed");
- }
- }
-
- // Init pset_loadavg function pointer
- init_pset_getloadavg_ptr();
-
- // Shared Posix initialization
- os::Posix::init_2();
-
- return JNI_OK;
-}
-
-// Is a (classpath) directory empty?
-bool os::dir_is_empty(const char* path) {
- DIR *dir = NULL;
- struct dirent *ptr;
-
- dir = opendir(path);
- if (dir == NULL) return true;
-
- // Scan the directory
- bool result = true;
- while (result && (ptr = readdir(dir)) != NULL) {
- if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) {
- result = false;
- }
- }
- closedir(dir);
- return result;
-}
-
-// This code originates from JDK's sysOpen and open64_w
-// from src/solaris/hpi/src/system_md.c
-
-int os::open(const char *path, int oflag, int mode) {
- if (strlen(path) > MAX_PATH - 1) {
- errno = ENAMETOOLONG;
- return -1;
- }
- int fd;
-
- fd = ::open64(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;
-
- if (ret != -1) {
- if ((st_mode & S_IFMT) == S_IFDIR) {
- errno = EISDIR;
- ::close(fd);
- return -1;
- }
- } else {
- ::close(fd);
- return -1;
- }
- }
-
- // 32-bit Solaris systems suffer from:
- //
- // - an historical default soft limit of 256 per-process file
- // descriptors that is too low for many Java programs.
- //
- // - a design flaw where file descriptors created using stdio
- // fopen must be less than 256, _even_ when the first limit above
- // has been raised. This can cause calls to fopen (but not calls to
- // open, for example) to fail mysteriously, perhaps in 3rd party
- // native code (although the JDK itself uses fopen). One can hardly
- // criticize them for using this most standard of all functions.
- //
- // We attempt to make everything work anyways by:
- //
- // - raising the soft limit on per-process file descriptors beyond
- // 256
- //
- // - As of Solaris 10u4, we can request that Solaris raise the 256
- // stdio fopen limit by calling function enable_extended_FILE_stdio.
- // This is done in init_2 and recorded in enabled_extended_FILE_stdio
- //
- // - If we are stuck on an old (pre 10u4) Solaris system, we can
- // workaround the bug by remapping non-stdio file descriptors below
- // 256 to ones beyond 256, which is done below.
- //
- // See:
- // 1085341: 32-bit stdio routines should support file descriptors >255
- // 6533291: Work around 32-bit Solaris stdio limit of 256 open files
- // 6431278: Netbeans crash on 32 bit Solaris: need to call
- // enable_extended_FILE_stdio() in VM initialisation
- // Giri Mandalika's blog
- // http://technopark02.blogspot.com/2005_05_01_archive.html
- //
-#ifndef _LP64
- if ((!enabled_extended_FILE_stdio) && fd < 256) {
- int newfd = ::fcntl(fd, F_DUPFD, 256);
- if (newfd != -1) {
- ::close(fd);
- fd = newfd;
- }
- }
-#endif // 32-bit Solaris
-
- // All file descriptors that are opened in the JVM and not
- // specifically destined for a subprocess should have the
- // close-on-exec flag set. If we don't set it, then careless 3rd
- // party native code might fork and exec without closing all
- // appropriate file descriptors (e.g. as we do in closeDescriptors in
- // UNIXProcess.c), and this in turn might:
- //
- // - cause end-of-file to fail to be detected on some file
- // descriptors, resulting in mysterious hangs, or
- //
- // - might cause an fopen in the subprocess to fail on a system
- // suffering from bug 1085341.
- //
- // (Yes, the default setting of the close-on-exec flag is a Unix
- // design flaw)
- //
- // See:
- // 1085341: 32-bit stdio routines should support file descriptors >255
- // 4843136: (process) pipe file descriptor from Runtime.exec not being closed
- // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9
- //
-#ifdef FD_CLOEXEC
- {
- int flags = ::fcntl(fd, F_GETFD);
- if (flags != -1) {
- ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
- }
- }
-#endif
-
- return fd;
-}
-
-// create binary file, rewriting existing file if required
-int os::create_binary_file(const char* path, bool rewrite_existing) {
- int oflags = O_WRONLY | O_CREAT;
- if (!rewrite_existing) {
- oflags |= O_EXCL;
- }
- return ::open64(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);
-}
-
-// 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);
-}
-
-jlong os::lseek(int fd, jlong offset, int whence) {
- return (jlong) ::lseek64(fd, offset, whence);
-}
-
-int os::ftruncate(int fd, jlong length) {
- return ::ftruncate64(fd, length);
-}
-
-int os::fsync(int fd) {
- RESTARTABLE_RETURN_INT(::fsync(fd));
-}
-
-int os::available(int fd, jlong *bytes) {
- assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native,
- "Assumed _thread_in_native");
- jlong cur, end;
- int mode;
- struct stat64 buf64;
-
- if (::fstat64(fd, &buf64) >= 0) {
- mode = buf64.st_mode;
- if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
- int n,ioctl_return;
-
- RESTARTABLE(::ioctl(fd, FIONREAD, &n), ioctl_return);
- if (ioctl_return>= 0) {
- *bytes = n;
- return 1;
- }
- }
- }
- if ((cur = ::lseek64(fd, 0L, SEEK_CUR)) == -1) {
- return 0;
- } else if ((end = ::lseek64(fd, 0L, SEEK_END)) == -1) {
- return 0;
- } else if (::lseek64(fd, cur, SEEK_SET) == -1) {
- return 0;
- }
- *bytes = end - cur;
- return 1;
-}
-
-// Map a block of memory.
-char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset,
- char *addr, size_t bytes, bool read_only,
- bool allow_exec) {
- int prot;
- int flags;
-
- if (read_only) {
- prot = PROT_READ;
- flags = MAP_SHARED;
- } else {
- prot = PROT_READ | PROT_WRITE;
- flags = MAP_PRIVATE;
- }
-
- if (allow_exec) {
- prot |= PROT_EXEC;
- }
-
- if (addr != NULL) {
- flags |= MAP_FIXED;
- }
-
- char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags,
- fd, file_offset);
- if (mapped_address == MAP_FAILED) {
- return NULL;
- }
- return mapped_address;
-}
-
-
-// Remap a block of memory.
-char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset,
- char *addr, size_t bytes, bool read_only,
- bool allow_exec) {
- // same as map_memory() on this OS
- return os::map_memory(fd, file_name, file_offset, addr, bytes, read_only,
- allow_exec);
-}
-
-
-// Unmap a block of memory.
-bool os::pd_unmap_memory(char* addr, size_t bytes) {
- return munmap(addr, bytes) == 0;
-}
-
-void os::pause() {
- char filename[MAX_PATH];
- if (PauseAtStartupFile && PauseAtStartupFile[0]) {
- jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile);
- } else {
- jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id());
- }
-
- int fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd != -1) {
- struct stat buf;
- ::close(fd);
- while (::stat(filename, &buf) == 0) {
- (void)::poll(NULL, 0, 100);
- }
- } else {
- jio_fprintf(stderr,
- "Could not open pause file '%s', continuing immediately.\n", filename);
- }
-}
-
-#ifndef PRODUCT
-#ifdef INTERPOSE_ON_SYSTEM_SYNCH_FUNCTIONS
-// Turn this on if you need to trace synch operations.
-// Set RECORD_SYNCH_LIMIT to a large-enough value,
-// and call record_synch_enable and record_synch_disable
-// around the computation of interest.
-
-void record_synch(char* name, bool returning); // defined below
-
-class RecordSynch {
- char* _name;
- public:
- RecordSynch(char* name) :_name(name) { record_synch(_name, false); }
- ~RecordSynch() { record_synch(_name, true); }
-};
-
-#define CHECK_SYNCH_OP(ret, name, params, args, inner) \
-extern "C" ret name params { \
- typedef ret name##_t params; \
- static name##_t* implem = NULL; \
- static int callcount = 0; \
- if (implem == NULL) { \
- implem = (name##_t*) dlsym(RTLD_NEXT, #name); \
- if (implem == NULL) fatal(dlerror()); \
- } \
- ++callcount; \
- RecordSynch _rs(#name); \
- inner; \
- return implem args; \
-}
-// in dbx, examine callcounts this way:
-// for n in $(eval whereis callcount | awk '{print $2}'); do print $n; done
-
-#define CHECK_POINTER_OK(p) \
- (!Universe::is_fully_initialized() || !Universe::is_reserved_heap((oop)(p)))
-#define CHECK_MU \
- if (!CHECK_POINTER_OK(mu)) fatal("Mutex must be in C heap only.");
-#define CHECK_CV \
- if (!CHECK_POINTER_OK(cv)) fatal("Condvar must be in C heap only.");
-#define CHECK_P(p) \
- if (!CHECK_POINTER_OK(p)) fatal(false, "Pointer must be in C heap only.");
-
-#define CHECK_MUTEX(mutex_op) \
- CHECK_SYNCH_OP(int, mutex_op, (mutex_t *mu), (mu), CHECK_MU);
-
-CHECK_MUTEX( mutex_lock)
-CHECK_MUTEX( _mutex_lock)
-CHECK_MUTEX( mutex_unlock)
-CHECK_MUTEX(_mutex_unlock)
-CHECK_MUTEX( mutex_trylock)
-CHECK_MUTEX(_mutex_trylock)
-
-#define CHECK_COND(cond_op) \
- CHECK_SYNCH_OP(int, cond_op, (cond_t *cv, mutex_t *mu), (cv, mu), CHECK_MU; CHECK_CV);
-
-CHECK_COND( cond_wait);
-CHECK_COND(_cond_wait);
-CHECK_COND(_cond_wait_cancel);
-
-#define CHECK_COND2(cond_op) \
- CHECK_SYNCH_OP(int, cond_op, (cond_t *cv, mutex_t *mu, timestruc_t* ts), (cv, mu, ts), CHECK_MU; CHECK_CV);
-
-CHECK_COND2( cond_timedwait);
-CHECK_COND2(_cond_timedwait);
-CHECK_COND2(_cond_timedwait_cancel);
-
-// do the _lwp_* versions too
-#define mutex_t lwp_mutex_t
-#define cond_t lwp_cond_t
-CHECK_MUTEX( _lwp_mutex_lock)
-CHECK_MUTEX( _lwp_mutex_unlock)
-CHECK_MUTEX( _lwp_mutex_trylock)
-CHECK_MUTEX( __lwp_mutex_lock)
-CHECK_MUTEX( __lwp_mutex_unlock)
-CHECK_MUTEX( __lwp_mutex_trylock)
-CHECK_MUTEX(___lwp_mutex_lock)
-CHECK_MUTEX(___lwp_mutex_unlock)
-
-CHECK_COND( _lwp_cond_wait);
-CHECK_COND( __lwp_cond_wait);
-CHECK_COND(___lwp_cond_wait);
-
-CHECK_COND2( _lwp_cond_timedwait);
-CHECK_COND2( __lwp_cond_timedwait);
-#undef mutex_t
-#undef cond_t
-
-CHECK_SYNCH_OP(int, _lwp_suspend2, (int lwp, int *n), (lwp, n), 0);
-CHECK_SYNCH_OP(int,__lwp_suspend2, (int lwp, int *n), (lwp, n), 0);
-CHECK_SYNCH_OP(int, _lwp_kill, (int lwp, int n), (lwp, n), 0);
-CHECK_SYNCH_OP(int,__lwp_kill, (int lwp, int n), (lwp, n), 0);
-CHECK_SYNCH_OP(int, _lwp_sema_wait, (lwp_sema_t* p), (p), CHECK_P(p));
-CHECK_SYNCH_OP(int,__lwp_sema_wait, (lwp_sema_t* p), (p), CHECK_P(p));
-CHECK_SYNCH_OP(int, _lwp_cond_broadcast, (lwp_cond_t* cv), (cv), CHECK_CV);
-CHECK_SYNCH_OP(int,__lwp_cond_broadcast, (lwp_cond_t* cv), (cv), CHECK_CV);
-
-
-// recording machinery:
-
-enum { RECORD_SYNCH_LIMIT = 200 };
-char* record_synch_name[RECORD_SYNCH_LIMIT];
-void* record_synch_arg0ptr[RECORD_SYNCH_LIMIT];
-bool record_synch_returning[RECORD_SYNCH_LIMIT];
-thread_t record_synch_thread[RECORD_SYNCH_LIMIT];
-int record_synch_count = 0;
-bool record_synch_enabled = false;
-
-// in dbx, examine recorded data this way:
-// for n in name arg0ptr returning thread; do print record_synch_$n[0..record_synch_count-1]; done
-
-void record_synch(char* name, bool returning) {
- if (record_synch_enabled) {
- if (record_synch_count < RECORD_SYNCH_LIMIT) {
- record_synch_name[record_synch_count] = name;
- record_synch_returning[record_synch_count] = returning;
- record_synch_thread[record_synch_count] = thr_self();
- record_synch_arg0ptr[record_synch_count] = &name;
- record_synch_count++;
- }
- // put more checking code here:
- // ...
- }
-}
-
-void record_synch_enable() {
- // start collecting trace data, if not already doing so
- if (!record_synch_enabled) record_synch_count = 0;
- record_synch_enabled = true;
-}
-
-void record_synch_disable() {
- // stop collecting trace data
- record_synch_enabled = false;
-}
-
-#endif // INTERPOSE_ON_SYSTEM_SYNCH_FUNCTIONS
-#endif // PRODUCT
-
-const intptr_t thr_time_off = (intptr_t)(&((prusage_t *)(NULL))->pr_utime);
-const intptr_t thr_time_size = (intptr_t)(&((prusage_t *)(NULL))->pr_ttime) -
- (intptr_t)(&((prusage_t *)(NULL))->pr_utime);
-
-
-// JVMTI & JVM monitoring and management support
-// The thread_cpu_time() and current_thread_cpu_time() are only
-// supported if is_thread_cpu_time_supported() returns true.
-// They are not supported on Solaris T1.
-
-// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool)
-// are used by JVM M&M and JVMTI to get user+sys or user CPU time
-// of a thread.
-//
-// current_thread_cpu_time() and thread_cpu_time(Thread *)
-// returns the fast estimate available on the platform.
-
-// hrtime_t gethrvtime() return value includes
-// user time but does not include system time
-jlong os::current_thread_cpu_time() {
- return (jlong) gethrvtime();
-}
-
-jlong os::thread_cpu_time(Thread *thread) {
- // return user level CPU time only to be consistent with
- // what current_thread_cpu_time returns.
- // thread_cpu_time_info() must be changed if this changes
- return os::thread_cpu_time(thread, false /* user time only */);
-}
-
-jlong os::current_thread_cpu_time(bool user_sys_cpu_time) {
- if (user_sys_cpu_time) {
- return os::thread_cpu_time(Thread::current(), user_sys_cpu_time);
- } else {
- return os::current_thread_cpu_time();
- }
-}
-
-jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
- char proc_name[64];
- int count;
- prusage_t prusage;
- jlong lwp_time;
- int fd;
-
- sprintf(proc_name, "/proc/%d/lwp/%d/lwpusage",
- getpid(),
- thread->osthread()->lwp_id());
- fd = ::open(proc_name, O_RDONLY);
- if (fd == -1) return -1;
-
- do {
- count = ::pread(fd,
- (void *)&prusage.pr_utime,
- thr_time_size,
- thr_time_off);
- } while (count < 0 && errno == EINTR);
- ::close(fd);
- if (count < 0) return -1;
-
- if (user_sys_cpu_time) {
- // user + system CPU time
- lwp_time = (((jlong)prusage.pr_stime.tv_sec +
- (jlong)prusage.pr_utime.tv_sec) * (jlong)1000000000) +
- (jlong)prusage.pr_stime.tv_nsec +
- (jlong)prusage.pr_utime.tv_nsec;
- } else {
- // user level CPU time only
- lwp_time = ((jlong)prusage.pr_utime.tv_sec * (jlong)1000000000) +
- (jlong)prusage.pr_utime.tv_nsec;
- }
-
- return (lwp_time);
-}
-
-void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
- info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
- info_ptr->may_skip_backward = false; // elapsed time not wall time
- info_ptr->may_skip_forward = false; // elapsed time not wall time
- info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned
-}
-
-void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
- info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
- info_ptr->may_skip_backward = false; // elapsed time not wall time
- info_ptr->may_skip_forward = false; // elapsed time not wall time
- info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned
-}
-
-bool os::is_thread_cpu_time_supported() {
- return true;
-}
-
-// System loadavg support. Returns -1 if load average cannot be obtained.
-// Return the load average for our processor set if the primitive exists
-// (Solaris 9 and later). Otherwise just return system wide loadavg.
-int os::loadavg(double loadavg[], int nelem) {
- if (pset_getloadavg_ptr != NULL) {
- return (*pset_getloadavg_ptr)(PS_MYID, loadavg, nelem);
- } else {
- return ::getloadavg(loadavg, nelem);
- }
-}
-
-//---------------------------------------------------------------------------------
-
-bool os::find(address addr, outputStream* st) {
- Dl_info dlinfo;
- memset(&dlinfo, 0, sizeof(dlinfo));
- if (dladdr(addr, &dlinfo) != 0) {
- st->print(PTR_FORMAT ": ", addr);
- if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) {
- st->print("%s+%#lx", dlinfo.dli_sname, addr-(intptr_t)dlinfo.dli_saddr);
- } else if (dlinfo.dli_fbase != NULL) {
- st->print("", addr-(intptr_t)dlinfo.dli_fbase);
- } else {
- st->print("");
- }
- if (dlinfo.dli_fname != NULL) {
- st->print(" in %s", dlinfo.dli_fname);
- }
- if (dlinfo.dli_fbase != NULL) {
- st->print(" at " PTR_FORMAT, dlinfo.dli_fbase);
- }
- st->cr();
-
- if (Verbose) {
- // decode some bytes around the PC
- address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size());
- address end = clamp_address_in_page(addr+40, addr, os::vm_page_size());
- address lowest = (address) dlinfo.dli_sname;
- if (!lowest) lowest = (address) dlinfo.dli_fbase;
- if (begin < lowest) begin = lowest;
- Dl_info dlinfo2;
- if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr
- && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) {
- end = (address) dlinfo2.dli_saddr;
- }
- Disassembler::decode(begin, end, st);
- }
- return true;
- }
- return false;
-}
-
-// Following function has been added to support HotSparc's libjvm.so running
-// under Solaris production JDK 1.2.2 / 1.3.0. These came from
-// src/solaris/hpi/native_threads in the EVM codebase.
-//
-// NOTE: This is no longer needed in the 1.3.1 and 1.4 production release
-// libraries and should thus be removed. We will leave it behind for a while
-// until we no longer want to able to run on top of 1.3.0 Solaris production
-// JDK. See 4341971.
-
-#define STACK_SLACK 0x800
-
-extern "C" {
- intptr_t sysThreadAvailableStackWithSlack() {
- stack_t st;
- intptr_t retval, stack_top;
- retval = thr_stksegment(&st);
- assert(retval == 0, "incorrect return value from thr_stksegment");
- assert((address)&st < (address)st.ss_sp, "Invalid stack base returned");
- assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned");
- stack_top=(intptr_t)st.ss_sp-st.ss_size;
- return ((intptr_t)&stack_top - stack_top - STACK_SLACK);
- }
-}
-
-// ObjectMonitor park-unpark infrastructure ...
-//
-// We implement Solaris and Linux PlatformEvents with the
-// obvious condvar-mutex-flag triple.
-// Another alternative that works quite well is pipes:
-// Each PlatformEvent consists of a pipe-pair.
-// The thread associated with the PlatformEvent
-// calls park(), which reads from the input end of the pipe.
-// Unpark() writes into the other end of the pipe.
-// The write-side of the pipe must be set NDELAY.
-// Unfortunately pipes consume a large # of handles.
-// Native solaris lwp_park() and lwp_unpark() work nicely, too.
-// Using pipes for the 1st few threads might be workable, however.
-//
-// park() is permitted to return spuriously.
-// Callers of park() should wrap the call to park() in
-// an appropriate loop. A litmus test for the correct
-// usage of park is the following: if park() were modified
-// to immediately return 0 your code should still work,
-// albeit degenerating to a spin loop.
-//
-// In a sense, park()-unpark() just provides more polite spinning
-// and polling with the key difference over naive spinning being
-// that a parked thread needs to be explicitly unparked() in order
-// to wake up and to poll the underlying condition.
-//
-// Assumption:
-// Only one parker can exist on an event, which is why we allocate
-// them per-thread. Multiple unparkers can coexist.
-//
-// _Event transitions in park()
-// -1 => -1 : illegal
-// 1 => 0 : pass - return immediately
-// 0 => -1 : block; then set _Event to 0 before returning
-//
-// _Event transitions in unpark()
-// 0 => 1 : just return
-// 1 => 1 : just return
-// -1 => either 0 or 1; must signal target thread
-// That is, we can safely transition _Event from -1 to either
-// 0 or 1.
-//
-// _Event serves as a restricted-range semaphore.
-// -1 : thread is blocked, i.e. there is a waiter
-// 0 : neutral: thread is running or ready,
-// could have been signaled after a wait started
-// 1 : signaled - thread is running or ready
-//
-// Another possible encoding of _Event would be with
-// explicit "PARKED" == 01b and "SIGNALED" == 10b bits.
-//
-// TODO-FIXME: add DTRACE probes for:
-// 1. Tx parks
-// 2. Ty unparks Tx
-// 3. Tx resumes from park
-
-
-// value determined through experimentation
-#define ROUNDINGFIX 11
-
-// utility to compute the abstime argument to timedwait.
-// TODO-FIXME: switch from compute_abstime() to unpackTime().
-
-static timestruc_t* compute_abstime(timestruc_t* abstime, jlong millis) {
- // millis is the relative timeout time
- // abstime will be the absolute timeout time
- if (millis < 0) millis = 0;
- struct timeval now;
- int status = gettimeofday(&now, NULL);
- assert(status == 0, "gettimeofday");
- jlong seconds = millis / 1000;
- jlong max_wait_period;
-
- if (UseLWPSynchronization) {
- // forward port of fix for 4275818 (not sleeping long enough)
- // There was a bug in Solaris 6, 7 and pre-patch 5 of 8 where
- // _lwp_cond_timedwait() used a round_down algorithm rather
- // than a round_up. For millis less than our roundfactor
- // it rounded down to 0 which doesn't meet the spec.
- // For millis > roundfactor we may return a bit sooner, but
- // since we can not accurately identify the patch level and
- // this has already been fixed in Solaris 9 and 8 we will
- // leave it alone rather than always rounding down.
-
- if (millis > 0 && millis < ROUNDINGFIX) millis = ROUNDINGFIX;
- // It appears that when we go directly through Solaris _lwp_cond_timedwait()
- // the acceptable max time threshold is smaller than for libthread on 2.5.1 and 2.6
- max_wait_period = 21000000;
- } else {
- max_wait_period = 50000000;
- }
- millis %= 1000;
- if (seconds > max_wait_period) { // see man cond_timedwait(3T)
- seconds = max_wait_period;
- }
- abstime->tv_sec = now.tv_sec + seconds;
- long usec = now.tv_usec + millis * 1000;
- if (usec >= 1000000) {
- abstime->tv_sec += 1;
- usec -= 1000000;
- }
- abstime->tv_nsec = usec * 1000;
- return abstime;
-}
-
-void os::PlatformEvent::park() { // AKA: down()
- // Transitions for _Event:
- // -1 => -1 : illegal
- // 1 => 0 : pass - return immediately
- // 0 => -1 : block; then set _Event to 0 before returning
-
- // Invariant: Only the thread associated with the Event/PlatformEvent
- // may call park().
- assert(_nParked == 0, "invariant");
-
- int v;
- for (;;) {
- v = _Event;
- if (Atomic::cmpxchg(&_Event, v, v-1) == v) break;
- }
- guarantee(v >= 0, "invariant");
- if (v == 0) {
- // Do this the hard way by blocking ...
- // See http://monaco.sfbay/detail.jsf?cr=5094058.
- int status = os::Solaris::mutex_lock(_mutex);
- assert_status(status == 0, status, "mutex_lock");
- guarantee(_nParked == 0, "invariant");
- ++_nParked;
- while (_Event < 0) {
- // for some reason, under 2.7 lwp_cond_wait() may return ETIME ...
- // Treat this the same as if the wait was interrupted
- // With usr/lib/lwp going to kernel, always handle ETIME
- status = os::Solaris::cond_wait(_cond, _mutex);
- if (status == ETIME) status = EINTR;
- assert_status(status == 0 || status == EINTR, status, "cond_wait");
- }
- --_nParked;
- _Event = 0;
- status = os::Solaris::mutex_unlock(_mutex);
- assert_status(status == 0, status, "mutex_unlock");
- // Paranoia to ensure our locked and lock-free paths interact
- // correctly with each other.
- OrderAccess::fence();
- }
-}
-
-int os::PlatformEvent::park(jlong millis) {
- // Transitions for _Event:
- // -1 => -1 : illegal
- // 1 => 0 : pass - return immediately
- // 0 => -1 : block; then set _Event to 0 before returning
-
- guarantee(_nParked == 0, "invariant");
- int v;
- for (;;) {
- v = _Event;
- if (Atomic::cmpxchg(&_Event, v, v-1) == v) break;
- }
- guarantee(v >= 0, "invariant");
- if (v != 0) return OS_OK;
-
- int ret = OS_TIMEOUT;
- timestruc_t abst;
- compute_abstime(&abst, millis);
-
- // See http://monaco.sfbay/detail.jsf?cr=5094058.
- int status = os::Solaris::mutex_lock(_mutex);
- assert_status(status == 0, status, "mutex_lock");
- guarantee(_nParked == 0, "invariant");
- ++_nParked;
- while (_Event < 0) {
- int status = os::Solaris::cond_timedwait(_cond, _mutex, &abst);
- assert_status(status == 0 || status == EINTR ||
- status == ETIME || status == ETIMEDOUT,
- status, "cond_timedwait");
- if (!FilterSpuriousWakeups) break; // previous semantics
- if (status == ETIME || status == ETIMEDOUT) break;
- // We consume and ignore EINTR and spurious wakeups.
- }
- --_nParked;
- if (_Event >= 0) ret = OS_OK;
- _Event = 0;
- status = os::Solaris::mutex_unlock(_mutex);
- assert_status(status == 0, status, "mutex_unlock");
- // Paranoia to ensure our locked and lock-free paths interact
- // correctly with each other.
- OrderAccess::fence();
- return ret;
-}
-
-void os::PlatformEvent::unpark() {
- // Transitions for _Event:
- // 0 => 1 : just return
- // 1 => 1 : just return
- // -1 => either 0 or 1; must signal target thread
- // That is, we can safely transition _Event from -1 to either
- // 0 or 1.
- // See also: "Semaphores in Plan 9" by Mullender & Cox
- //
- // Note: Forcing a transition from "-1" to "1" on an unpark() means
- // that it will take two back-to-back park() calls for the owning
- // thread to block. This has the benefit of forcing a spurious return
- // from the first park() call after an unpark() call which will help
- // shake out uses of park() and unpark() without condition variables.
-
- if (Atomic::xchg(&_Event, 1) >= 0) return;
-
- // If the thread associated with the event was parked, wake it.
- // Wait for the thread assoc with the PlatformEvent to vacate.
- int status = os::Solaris::mutex_lock(_mutex);
- assert_status(status == 0, status, "mutex_lock");
- int AnyWaiters = _nParked;
- status = os::Solaris::mutex_unlock(_mutex);
- assert_status(status == 0, status, "mutex_unlock");
- guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
- if (AnyWaiters != 0) {
- // Note that we signal() *after* dropping the lock for "immortal" Events.
- // This is safe and avoids a common class of futile wakeups. In rare
- // circumstances this can cause a thread to return prematurely from
- // cond_{timed}wait() but the spurious wakeup is benign and the victim
- // will simply re-test the condition and re-park itself.
- // This provides particular benefit if the underlying platform does not
- // provide wait morphing.
- status = os::Solaris::cond_signal(_cond);
- assert_status(status == 0, status, "cond_signal");
- }
-}
-
-// JSR166
-// -------------------------------------------------------
-
-// The solaris and linux implementations of park/unpark are fairly
-// conservative for now, but can be improved. They currently use a
-// mutex/condvar pair, plus _counter.
-// Park decrements _counter if > 0, else does a condvar wait. Unpark
-// sets count to 1 and signals condvar. Only one thread ever waits
-// on the condvar. Contention seen when trying to park implies that someone
-// is unparking you, so don't wait. And spurious returns are fine, so there
-// is no need to track notifications.
-
-#define MAX_SECS 100000000
-
-// This code is common to linux and solaris and will be moved to a
-// common place in dolphin.
-//
-// The passed in time value is either a relative time in nanoseconds
-// or an absolute time in milliseconds. Either way it has to be unpacked
-// into suitable seconds and nanoseconds components and stored in the
-// given timespec structure.
-// Given time is a 64-bit value and the time_t used in the timespec is only
-// a signed-32-bit value (except on 64-bit Linux) we have to watch for
-// overflow if times way in the future are given. Further on Solaris versions
-// prior to 10 there is a restriction (see cond_timedwait) that the specified
-// number of seconds, in abstime, is less than current_time + 100,000,000.
-// As it will be 28 years before "now + 100000000" will overflow we can
-// ignore overflow and just impose a hard-limit on seconds using the value
-// of "now + 100,000,000". This places a limit on the timeout of about 3.17
-// years from "now".
-//
-static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) {
- assert(time > 0, "convertTime");
-
- struct timeval now;
- int status = gettimeofday(&now, NULL);
- assert(status == 0, "gettimeofday");
-
- time_t max_secs = now.tv_sec + MAX_SECS;
-
- if (isAbsolute) {
- jlong secs = time / 1000;
- if (secs > max_secs) {
- absTime->tv_sec = max_secs;
- } else {
- absTime->tv_sec = secs;
- }
- absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC;
- } else {
- jlong secs = time / NANOSECS_PER_SEC;
- if (secs >= MAX_SECS) {
- absTime->tv_sec = max_secs;
- absTime->tv_nsec = 0;
- } else {
- absTime->tv_sec = now.tv_sec + secs;
- absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000;
- if (absTime->tv_nsec >= NANOSECS_PER_SEC) {
- absTime->tv_nsec -= NANOSECS_PER_SEC;
- ++absTime->tv_sec; // note: this must be <= max_secs
- }
- }
- }
- assert(absTime->tv_sec >= 0, "tv_sec < 0");
- assert(absTime->tv_sec <= max_secs, "tv_sec > max_secs");
- assert(absTime->tv_nsec >= 0, "tv_nsec < 0");
- assert(absTime->tv_nsec < NANOSECS_PER_SEC, "tv_nsec >= nanos_per_sec");
-}
-
-void Parker::park(bool isAbsolute, jlong time) {
- // Ideally we'd do something useful while spinning, such
- // as calling unpackTime().
-
- // Optional fast-path check:
- // Return immediately if a permit is available.
- // We depend on Atomic::xchg() having full barrier semantics
- // since we are doing a lock-free update to _counter.
- if (Atomic::xchg(&_counter, 0) > 0) return;
-
- // Optional fast-exit: Check interrupt before trying to wait
- Thread* thread = Thread::current();
- assert(thread->is_Java_thread(), "Must be JavaThread");
- JavaThread *jt = (JavaThread *)thread;
- if (jt->is_interrupted(false)) {
- return;
- }
-
- // First, demultiplex/decode time arguments
- timespec absTime;
- if (time < 0 || (isAbsolute && time == 0)) { // don't wait at all
- return;
- }
- if (time > 0) {
- // Warning: this code might be exposed to the old Solaris time
- // round-down bugs. Grep "roundingFix" for details.
- unpackTime(&absTime, isAbsolute, time);
- }
-
- // Enter safepoint region
- // Beware of deadlocks such as 6317397.
- // The per-thread Parker:: _mutex is a classic leaf-lock.
- // In particular a thread must never block on the Threads_lock while
- // holding the Parker:: mutex. If safepoints are pending both the
- // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
- ThreadBlockInVM tbivm(jt);
-
- // Can't access interrupt state now that we are _thread_blocked. If we've
- // been interrupted since we checked above then _counter will be > 0.
-
- // Don't wait if cannot get lock since interference arises from
- // unblocking.
- if (os::Solaris::mutex_trylock(_mutex) != 0) {
- return;
- }
-
- int status;
-
- if (_counter > 0) { // no wait needed
- _counter = 0;
- status = os::Solaris::mutex_unlock(_mutex);
- assert(status == 0, "invariant");
- // Paranoia to ensure our locked and lock-free paths interact
- // correctly with each other and Java-level accesses.
- OrderAccess::fence();
- return;
- }
-
- OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
- jt->set_suspend_equivalent();
- // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
-
- // Do this the hard way by blocking ...
- // See http://monaco.sfbay/detail.jsf?cr=5094058.
- if (time == 0) {
- status = os::Solaris::cond_wait(_cond, _mutex);
- } else {
- status = os::Solaris::cond_timedwait (_cond, _mutex, &absTime);
- }
- // Note that an untimed cond_wait() can sometimes return ETIME on older
- // versions of the Solaris.
- assert_status(status == 0 || status == EINTR ||
- status == ETIME || status == ETIMEDOUT,
- status, "cond_timedwait");
-
- _counter = 0;
- status = os::Solaris::mutex_unlock(_mutex);
- assert_status(status == 0, status, "mutex_unlock");
- // Paranoia to ensure our locked and lock-free paths interact
- // correctly with each other and Java-level accesses.
- OrderAccess::fence();
-
- // If externally suspended while waiting, re-suspend
- if (jt->handle_special_suspend_equivalent_condition()) {
- jt->java_suspend_self();
- }
-}
-
-void Parker::unpark() {
- int status = os::Solaris::mutex_lock(_mutex);
- assert(status == 0, "invariant");
- const int s = _counter;
- _counter = 1;
- status = os::Solaris::mutex_unlock(_mutex);
- assert(status == 0, "invariant");
-
- if (s < 1) {
- status = os::Solaris::cond_signal(_cond);
- assert(status == 0, "invariant");
- }
-}
-
-// Platform Mutex/Monitor implementations
-
-os::PlatformMutex::PlatformMutex() {
- int status = os::Solaris::mutex_init(&_mutex);
- assert_status(status == 0, status, "mutex_init");
-}
-
-os::PlatformMutex::~PlatformMutex() {
- int status = os::Solaris::mutex_destroy(&_mutex);
- assert_status(status == 0, status, "mutex_destroy");
-}
-
-void os::PlatformMutex::lock() {
- int status = os::Solaris::mutex_lock(&_mutex);
- assert_status(status == 0, status, "mutex_lock");
-}
-
-void os::PlatformMutex::unlock() {
- int status = os::Solaris::mutex_unlock(&_mutex);
- assert_status(status == 0, status, "mutex_unlock");
-}
-
-bool os::PlatformMutex::try_lock() {
- int status = os::Solaris::mutex_trylock(&_mutex);
- assert_status(status == 0 || status == EBUSY, status, "mutex_trylock");
- return status == 0;
-}
-
-os::PlatformMonitor::PlatformMonitor() {
- int status = os::Solaris::cond_init(&_cond);
- assert_status(status == 0, status, "cond_init");
-}
-
-os::PlatformMonitor::~PlatformMonitor() {
- int status = os::Solaris::cond_destroy(&_cond);
- assert_status(status == 0, status, "cond_destroy");
-}
-
-// Must already be locked
-int os::PlatformMonitor::wait(jlong millis) {
- assert(millis >= 0, "negative timeout");
- if (millis > 0) {
- timestruc_t abst;
- int ret = OS_TIMEOUT;
- compute_abstime(&abst, millis);
- int status = os::Solaris::cond_timedwait(&_cond, &_mutex, &abst);
- assert_status(status == 0 || status == EINTR ||
- status == ETIME || status == ETIMEDOUT,
- status, "cond_timedwait");
- // EINTR acts as spurious wakeup - which is permitted anyway
- if (status == 0 || status == EINTR) {
- ret = OS_OK;
- }
- return ret;
- } else {
- int status = os::Solaris::cond_wait(&_cond, &_mutex);
- assert_status(status == 0 || status == EINTR,
- status, "cond_wait");
- return OS_OK;
- }
-}
-
-void os::PlatformMonitor::notify() {
- int status = os::Solaris::cond_signal(&_cond);
- assert_status(status == 0, status, "cond_signal");
-}
-
-void os::PlatformMonitor::notify_all() {
- int status = os::Solaris::cond_broadcast(&_cond);
- assert_status(status == 0, status, "cond_broadcast");
-}
-
-extern char** environ;
-
-// Run the specified command in a separate process. Return its exit value,
-// or -1 on failure (e.g. can't fork a new process).
-// Unlike system(), this function can be called from signal handler. It
-// doesn't block SIGINT et al.
-int os::fork_and_exec(char* cmd, bool use_vfork_if_available) {
- char * argv[4];
- argv[0] = (char *)"sh";
- argv[1] = (char *)"-c";
- argv[2] = cmd;
- argv[3] = NULL;
-
- // fork is async-safe, fork1 is not so can't use in signal handler
- pid_t pid;
- Thread* t = Thread::current_or_null_safe();
- if (t != NULL && t->is_inside_signal_handler()) {
- pid = fork();
- } else {
- pid = fork1();
- }
-
- if (pid < 0) {
- // fork failed
- warning("fork failed: %s", os::strerror(errno));
- return -1;
-
- } else if (pid == 0) {
- // child process
-
- // try to be consistent with system(), which uses "/usr/bin/sh" on Solaris
- execve("/usr/bin/sh", argv, environ);
-
- // execve failed
- _exit(-1);
-
- } else {
- // copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
- // care about the actual exit code, for now.
-
- int status;
-
- // Wait for the child process to exit. This returns immediately if
- // the child has already exited. */
- while (waitpid(pid, &status, 0) < 0) {
- switch (errno) {
- case ECHILD: return 0;
- case EINTR: break;
- default: return -1;
- }
- }
-
- if (WIFEXITED(status)) {
- // The child exited normally; get its exit code.
- return WEXITSTATUS(status);
- } else if (WIFSIGNALED(status)) {
- // The child exited because of a signal
- // The best value to return is 0x80 + signal number,
- // because that is what all Unix shells do, and because
- // it allows callers to distinguish between process exit and
- // process death by signal.
- return 0x80 + WTERMSIG(status);
- } else {
- // Unknown exit code; pass it through
- return status;
- }
- }
-}
-
-size_t os::write(int fd, const void *buf, unsigned int nBytes) {
- size_t res;
- RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res);
- return res;
-}
-
-int os::close(int fd) {
- return ::close(fd);
-}
-
-int os::socket_close(int fd) {
- return ::close(fd);
-}
-
-int os::recv(int fd, char* buf, size_t nBytes, uint flags) {
- assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native,
- "Assumed _thread_in_native");
- RESTARTABLE_RETURN_INT((int)::recv(fd, buf, nBytes, flags));
-}
-
-int os::send(int fd, char* buf, size_t nBytes, uint flags) {
- assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native,
- "Assumed _thread_in_native");
- RESTARTABLE_RETURN_INT((int)::send(fd, buf, nBytes, flags));
-}
-
-int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) {
- RESTARTABLE_RETURN_INT((int)::send(fd, buf, nBytes, flags));
-}
-
-// As both poll and select can be interrupted by signals, we have to be
-// prepared to restart the system call after updating the timeout, unless
-// a poll() is done with timeout == -1, in which case we repeat with this
-// "wait forever" value.
-
-int os::connect(int fd, struct sockaddr *him, socklen_t len) {
- int _result;
- _result = ::connect(fd, him, len);
-
- // On Solaris, when a connect() call is interrupted, the connection
- // can be established asynchronously (see 6343810). Subsequent calls
- // to connect() must check the errno value which has the semantic
- // described below (copied from the connect() man page). Handling
- // of asynchronously established connections is required for both
- // blocking and non-blocking sockets.
- // EINTR The connection attempt was interrupted
- // before any data arrived by the delivery of
- // a signal. The connection, however, will be
- // established asynchronously.
- //
- // EINPROGRESS The socket is non-blocking, and the connec-
- // tion cannot be completed immediately.
- //
- // EALREADY The socket is non-blocking, and a previous
- // connection attempt has not yet been com-
- // pleted.
- //
- // EISCONN The socket is already connected.
- if (_result == OS_ERR && errno == EINTR) {
- // restarting a connect() changes its errno semantics
- RESTARTABLE(::connect(fd, him, len), _result);
- // undo these changes
- if (_result == OS_ERR) {
- if (errno == EALREADY) {
- errno = EINPROGRESS; // fall through
- } else if (errno == EISCONN) {
- errno = 0;
- return OS_OK;
- }
- }
- }
- return _result;
-}
-
-// Get the default path to the core file
-// Returns the length of the string
-int os::get_core_path(char* buffer, size_t bufferSize) {
- const char* p = get_current_directory(buffer, bufferSize);
-
- if (p == NULL) {
- assert(p != NULL, "failed to get current directory");
- return 0;
- }
-
- jio_snprintf(buffer, bufferSize, "%s/core or core.%d",
- p, current_process_id());
-
- return strlen(buffer);
-}
-
-bool os::supports_map_sync() {
- return false;
-}
-
-#ifndef PRODUCT
-void TestReserveMemorySpecial_test() {
- // No tests available for this platform
-}
-#endif
-
-bool os::start_debugging(char *buf, int buflen) {
- int len = (int)strlen(buf);
- char *p = &buf[len];
-
- jio_snprintf(p, buflen-len,
- "\n\n"
- "Do you want to debug the problem?\n\n"
- "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n"
- "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n"
- "Otherwise, press RETURN to abort...",
- os::current_process_id(), os::current_thread_id());
-
- bool yes = os::message_box("Unexpected Error", buf);
-
- if (yes) {
- // yes, user asked VM to launch debugger
- jio_snprintf(buf, sizeof(buf), "dbx - %d", os::current_process_id());
-
- os::fork_and_exec(buf);
- yes = false;
- }
- return yes;
-}
diff --git a/src/hotspot/os/solaris/os_solaris.hpp b/src/hotspot/os/solaris/os_solaris.hpp
deleted file mode 100644
index 6464277abf4..00000000000
--- a/src/hotspot/os/solaris/os_solaris.hpp
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_OS_SOLARIS_HPP
-#define OS_SOLARIS_OS_SOLARIS_HPP
-
-// Solaris_OS defines the interface to Solaris operating systems
-
-// see thr_setprio(3T) for the basis of these numbers
-#define MinimumPriority 0
-#define NormalPriority 64
-#define MaximumPriority 127
-
-// FX/60 is critical thread class/priority on T4
-#define FXCriticalPriority 60
-
-// Information about the protection of the page at address '0' on this os.
-static bool zero_page_read_protected() { return true; }
-
-class Solaris {
- friend class os;
-
- private:
-
- // Support for "new" libthread APIs for getting & setting thread context (2.8)
-#define TRS_VALID 0
-#define TRS_NONVOLATILE 1
-#define TRS_LWPID 2
-#define TRS_INVALID 3
-
- // initialized to libthread or lwp synchronization primitives depending on UseLWPSychronization
- static int_fnP_mutex_tP _mutex_lock;
- static int_fnP_mutex_tP _mutex_trylock;
- static int_fnP_mutex_tP _mutex_unlock;
- static int_fnP_mutex_tP_i_vP _mutex_init;
- static int_fnP_mutex_tP _mutex_destroy;
- static int _mutex_scope;
-
- static int_fnP_cond_tP_mutex_tP_timestruc_tP _cond_timedwait;
- static int_fnP_cond_tP_mutex_tP _cond_wait;
- static int_fnP_cond_tP _cond_signal;
- static int_fnP_cond_tP _cond_broadcast;
- static int_fnP_cond_tP_i_vP _cond_init;
- static int_fnP_cond_tP _cond_destroy;
- static int _cond_scope;
-
- static bool _synchronization_initialized;
-
- typedef uintptr_t lgrp_cookie_t;
- typedef id_t lgrp_id_t;
- typedef int lgrp_rsrc_t;
- typedef enum lgrp_view {
- LGRP_VIEW_CALLER, // what's available to the caller
- LGRP_VIEW_OS // what's available to operating system
- } lgrp_view_t;
-
- typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id);
- typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view);
- typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie);
- typedef lgrp_id_t (*lgrp_root_func_t)(lgrp_cookie_t cookie);
- typedef int (*lgrp_children_func_t)(lgrp_cookie_t cookie, lgrp_id_t parent,
- lgrp_id_t *lgrp_array, uint_t lgrp_array_size);
- typedef int (*lgrp_resources_func_t)(lgrp_cookie_t cookie, lgrp_id_t lgrp,
- lgrp_id_t *lgrp_array, uint_t lgrp_array_size,
- lgrp_rsrc_t type);
- typedef int (*lgrp_nlgrps_func_t)(lgrp_cookie_t cookie);
- typedef int (*lgrp_cookie_stale_func_t)(lgrp_cookie_t cookie);
-
- static lgrp_home_func_t _lgrp_home;
- static lgrp_init_func_t _lgrp_init;
- static lgrp_fini_func_t _lgrp_fini;
- static lgrp_root_func_t _lgrp_root;
- static lgrp_children_func_t _lgrp_children;
- static lgrp_resources_func_t _lgrp_resources;
- static lgrp_nlgrps_func_t _lgrp_nlgrps;
- static lgrp_cookie_stale_func_t _lgrp_cookie_stale;
- static lgrp_cookie_t _lgrp_cookie;
-
- // Large Page Support
- static bool is_valid_page_size(size_t bytes);
- static size_t page_size_for_alignment(size_t alignment);
- static bool setup_large_pages(caddr_t start, size_t bytes, size_t align);
-
- static void try_enable_extended_io();
-
- static struct sigaction *(*get_signal_action)(int);
- static struct sigaction *get_preinstalled_handler(int);
- static int (*get_libjsig_version)();
- static void save_preinstalled_handler(int, struct sigaction&);
- static void check_signal_handler(int sig);
-
- typedef int (*pthread_setname_np_func_t)(pthread_t, const char*);
- static pthread_setname_np_func_t _pthread_setname_np;
-
- public:
- // Large Page Support--ISM.
- static bool largepage_range(char* addr, size_t size);
-
- static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo
-
- static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect);
- static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread,
- const ucontext_t* uc);
-
- static ExtendedPC ucontext_get_ExtendedPC(const ucontext_t* uc);
- static intptr_t* ucontext_get_sp(const ucontext_t* uc);
- // ucontext_get_fp() is only used by Solaris X86 (see note below)
- static intptr_t* ucontext_get_fp(const ucontext_t* uc);
- static address ucontext_get_pc(const ucontext_t* uc);
- static void ucontext_set_pc(ucontext_t* uc, address pc);
-
- // For Analyzer Forte AsyncGetCallTrace profiling support:
- // Parameter ret_fp is only used by Solaris X86.
- //
- // We should have different declarations of this interface in
- // os_solaris_i486.hpp and os_solaris_sparc.hpp, but that file
- // provides extensions to the os class and not the Solaris class.
- static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc,
- intptr_t** ret_sp, intptr_t** ret_fp);
-
- static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
-
- static void hotspot_sigmask(Thread* thread);
-
- // SR_handler
- static void SR_handler(Thread* thread, ucontext_t* uc);
-
- static void init_thread_fpu_state(void);
-
- protected:
- // Solaris-specific interface goes here
- static julong available_memory();
- static julong physical_memory() { return _physical_memory; }
- static julong _physical_memory;
- static void initialize_system_info();
- static int _dev_zero_fd;
- static int get_dev_zero_fd() { return _dev_zero_fd; }
- static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; }
- static int commit_memory_impl(char* addr, size_t bytes, bool exec);
- static int commit_memory_impl(char* addr, size_t bytes,
- size_t alignment_hint, bool exec);
- static char* mmap_chunk(char *addr, size_t size, int flags, int prot);
- static char* anon_mmap(char* requested_addr, size_t bytes, size_t alignment_hint, bool fixed);
- static bool mpss_sanity_check(bool warn, size_t * page_size);
-
- // Workaround for 4352906. thr_stksegment sometimes returns
- // a bad value for the primordial thread's stack base when
- // it is called more than one time.
- // Workaround is to cache the initial value to avoid further
- // calls to thr_stksegment.
- // It appears that someone (Hotspot?) is trashing the user's
- // proc_t structure (note that this is a system struct).
- static address _main_stack_base;
-
- static void print_distro_info(outputStream* st);
- static void print_libversion_info(outputStream* st);
-
- public:
- static void libthread_init();
- static void synchronization_init();
- static bool liblgrp_init();
- // This boolean allows users to forward their own non-matching signals
- // to JVM_handle_solaris_signal, harmlessly.
- static bool signal_handlers_are_installed;
-
- static void signal_sets_init();
- static void install_signal_handlers();
- static void set_signal_handler(int sig, bool set_installed, bool oktochain);
- static void init_signal_mem();
- static void set_our_sigflags(int, int);
- static int get_our_sigflags(int);
-
- // For signal-chaining
- static bool libjsig_is_loaded; // libjsig that interposes sigaction(),
- // signal(), sigset() is loaded
- static struct sigaction *get_chained_signal_action(int sig);
- static bool chained_handler(int sig, siginfo_t *siginfo, void *context);
-
- // Allows us to switch between lwp and thread -based synchronization
- static int mutex_lock(mutex_t *mx) { return _mutex_lock(mx); }
- static int mutex_trylock(mutex_t *mx) { return _mutex_trylock(mx); }
- static int mutex_unlock(mutex_t *mx) { return _mutex_unlock(mx); }
- static int mutex_init(mutex_t *mx) { return _mutex_init(mx, os::Solaris::mutex_scope(), NULL); }
- static int mutex_destroy(mutex_t *mx) { return _mutex_destroy(mx); }
- static int mutex_scope() { return _mutex_scope; }
-
- static void set_mutex_lock(int_fnP_mutex_tP func) { _mutex_lock = func; }
- static void set_mutex_trylock(int_fnP_mutex_tP func) { _mutex_trylock = func; }
- static void set_mutex_unlock(int_fnP_mutex_tP func) { _mutex_unlock = func; }
- static void set_mutex_init(int_fnP_mutex_tP_i_vP func) { _mutex_init = func; }
- static void set_mutex_destroy(int_fnP_mutex_tP func) { _mutex_destroy = func; }
- static void set_mutex_scope(int scope) { _mutex_scope = scope; }
-
- static int cond_timedwait(cond_t *cv, mutex_t *mx, timestruc_t *abst) { return _cond_timedwait(cv, mx, abst); }
- static int cond_wait(cond_t *cv, mutex_t *mx) { return _cond_wait(cv, mx); }
- static int cond_signal(cond_t *cv) { return _cond_signal(cv); }
- static int cond_broadcast(cond_t *cv) { return _cond_broadcast(cv); }
- static int cond_init(cond_t *cv) { return _cond_init(cv, os::Solaris::cond_scope(), NULL); }
- static int cond_destroy(cond_t *cv) { return _cond_destroy(cv); }
- static int cond_scope() { return _cond_scope; }
-
- static void set_cond_timedwait(int_fnP_cond_tP_mutex_tP_timestruc_tP func) { _cond_timedwait = func; }
- static void set_cond_wait(int_fnP_cond_tP_mutex_tP func) { _cond_wait = func; }
- static void set_cond_signal(int_fnP_cond_tP func) { _cond_signal = func; }
- static void set_cond_broadcast(int_fnP_cond_tP func) { _cond_broadcast = func; }
- static void set_cond_init(int_fnP_cond_tP_i_vP func) { _cond_init = func; }
- static void set_cond_destroy(int_fnP_cond_tP func) { _cond_destroy = func; }
- static void set_cond_scope(int scope) { _cond_scope = scope; }
-
- static bool synchronization_initialized() { return _synchronization_initialized; }
-
- static void set_lgrp_home(lgrp_home_func_t func) { _lgrp_home = func; }
- static void set_lgrp_init(lgrp_init_func_t func) { _lgrp_init = func; }
- static void set_lgrp_fini(lgrp_fini_func_t func) { _lgrp_fini = func; }
- static void set_lgrp_root(lgrp_root_func_t func) { _lgrp_root = func; }
- static void set_lgrp_children(lgrp_children_func_t func) { _lgrp_children = func; }
- static void set_lgrp_resources(lgrp_resources_func_t func) { _lgrp_resources = func; }
- static void set_lgrp_nlgrps(lgrp_nlgrps_func_t func) { _lgrp_nlgrps = func; }
- static void set_lgrp_cookie_stale(lgrp_cookie_stale_func_t func) { _lgrp_cookie_stale = func; }
- static void set_lgrp_cookie(lgrp_cookie_t cookie) { _lgrp_cookie = cookie; }
-
- static id_t lgrp_home(idtype_t type, id_t id) { return _lgrp_home != NULL ? _lgrp_home(type, id) : -1; }
- static lgrp_cookie_t lgrp_init(lgrp_view_t view) { return _lgrp_init != NULL ? _lgrp_init(view) : 0; }
- static int lgrp_fini(lgrp_cookie_t cookie) { return _lgrp_fini != NULL ? _lgrp_fini(cookie) : -1; }
- static lgrp_id_t lgrp_root(lgrp_cookie_t cookie) { return _lgrp_root != NULL ? _lgrp_root(cookie) : -1; }
- static int lgrp_children(lgrp_cookie_t cookie, lgrp_id_t parent,
- lgrp_id_t *lgrp_array, uint_t lgrp_array_size) {
- return _lgrp_children != NULL ? _lgrp_children(cookie, parent, lgrp_array, lgrp_array_size) : -1;
- }
- static int lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp,
- lgrp_id_t *lgrp_array, uint_t lgrp_array_size,
- lgrp_rsrc_t type) {
- return _lgrp_resources != NULL ? _lgrp_resources(cookie, lgrp, lgrp_array, lgrp_array_size, type) : -1;
- }
-
- static int lgrp_nlgrps(lgrp_cookie_t cookie) { return _lgrp_nlgrps != NULL ? _lgrp_nlgrps(cookie) : -1; }
- static int lgrp_cookie_stale(lgrp_cookie_t cookie) {
- return _lgrp_cookie_stale != NULL ? _lgrp_cookie_stale(cookie) : -1;
- }
- static lgrp_cookie_t lgrp_cookie() { return _lgrp_cookie; }
-
- static sigset_t* unblocked_signals();
- static sigset_t* vm_signals();
-
- // %%% Following should be promoted to os.hpp:
- // Trace number of created threads
- static jint _os_thread_limit;
- static volatile jint _os_thread_count;
-
- static void correct_stack_boundaries_for_primordial_thread(Thread* thr);
-
- // Stack repair handling
-
- // none present
-
-};
-
-class PlatformEvent : public CHeapObj {
- private:
- double CachePad[4]; // increase odds that _mutex is sole occupant of cache line
- volatile int _Event;
- int _nParked;
- int _pipev[2];
- mutex_t _mutex[1];
- cond_t _cond[1];
- double PostPad[2];
-
- protected:
- // Defining a protected ctor effectively gives us an abstract base class.
- // That is, a PlatformEvent can never be instantiated "naked" but only
- // as a part of a ParkEvent (recall that ParkEvent extends PlatformEvent).
- // TODO-FIXME: make dtor private
- ~PlatformEvent() { guarantee(0, "invariant"); }
- PlatformEvent() {
- int status;
- status = os::Solaris::cond_init(_cond);
- assert_status(status == 0, status, "cond_init");
- status = os::Solaris::mutex_init(_mutex);
- assert_status(status == 0, status, "mutex_init");
- _Event = 0;
- _nParked = 0;
- _pipev[0] = _pipev[1] = -1;
- }
-
- public:
- // Exercise caution using reset() and fired() -- they may require MEMBARs
- void reset() { _Event = 0; }
- int fired() { return _Event; }
- void park();
- int park(jlong millis);
- void unpark();
-};
-
-class PlatformParker : public CHeapObj {
- protected:
- mutex_t _mutex[1];
- cond_t _cond[1];
-
- public: // TODO-FIXME: make dtor private
- ~PlatformParker() { guarantee(0, "invariant"); }
-
- public:
- PlatformParker() {
- int status;
- status = os::Solaris::cond_init(_cond);
- assert_status(status == 0, status, "cond_init");
- status = os::Solaris::mutex_init(_mutex);
- assert_status(status == 0, status, "mutex_init");
- }
-};
-
-// Platform specific implementations that underpin VM Mutex/Monitor classes
-
-class PlatformMutex : public CHeapObj {
- NONCOPYABLE(PlatformMutex);
-
- protected:
- mutex_t _mutex; // Native mutex for locking
-
- public:
- PlatformMutex();
- ~PlatformMutex();
- void lock();
- void unlock();
- bool try_lock();
-};
-
-class PlatformMonitor : public PlatformMutex {
- private:
- cond_t _cond; // Native condition variable for blocking
-
- NONCOPYABLE(PlatformMonitor);
-
- public:
- PlatformMonitor();
- ~PlatformMonitor();
- int wait(jlong millis);
- void notify();
- void notify_all();
-};
-
-#endif // OS_SOLARIS_OS_SOLARIS_HPP
diff --git a/src/hotspot/os/solaris/os_solaris.inline.hpp b/src/hotspot/os/solaris/os_solaris.inline.hpp
deleted file mode 100644
index f1d2aca97f1..00000000000
--- a/src/hotspot/os/solaris/os_solaris.inline.hpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_OS_SOLARIS_INLINE_HPP
-#define OS_SOLARIS_OS_SOLARIS_INLINE_HPP
-
-#include "runtime/os.hpp"
-
-// System includes
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-inline bool os::uses_stack_guard_pages() {
- return true;
-}
-
-inline bool os::must_commit_stack_guard_pages() {
- assert(uses_stack_guard_pages(), "sanity check");
- int r = thr_main() ;
- guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ;
- return r;
-}
-
-
-// Bang the shadow pages if they need to be touched to be mapped.
-inline void os::map_stack_shadow_pages(address sp) {
-}
-
-inline void os::dll_unload(void *lib) { ::dlclose(lib); }
-
-//////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-// macros for restartable system calls
-
-#define RESTARTABLE(_cmd, _result) do { \
- do { \
- _result = _cmd; \
- } while((_result == OS_ERR) && (errno == EINTR)); \
-} while(false)
-
-#define RESTARTABLE_RETURN_INT(_cmd) do { \
- int _result; \
- RESTARTABLE(_cmd, _result); \
- return _result; \
-} while(false)
-
-inline bool os::numa_has_static_binding() { return false; }
-inline bool os::numa_has_group_homing() { return true; }
-
-inline int os::socket(int domain, int type, int protocol) {
- return ::socket(domain, type, protocol);
-}
-
-inline struct hostent* os::get_host_by_name(char* name) {
- return ::gethostbyname(name);
-}
-
-inline bool os::supports_monotonic_clock() {
- // javaTimeNanos() is monotonic on Solaris, see getTimeNanos() comments
- return true;
-}
-
-inline void os::exit(int num) {
- ::exit(num);
-}
-
-#endif // OS_SOLARIS_OS_SOLARIS_INLINE_HPP
diff --git a/src/hotspot/os/solaris/perfMemory_solaris.cpp b/src/hotspot/os/solaris/perfMemory_solaris.cpp
deleted file mode 100644
index 1d2c415ab55..00000000000
--- a/src/hotspot/os/solaris/perfMemory_solaris.cpp
+++ /dev/null
@@ -1,1294 +0,0 @@
-/*
- * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "classfile/vmSymbols.hpp"
-#include "logging/log.hpp"
-#include "memory/allocation.inline.hpp"
-#include "memory/resourceArea.hpp"
-#include "oops/oop.inline.hpp"
-#include "os_solaris.inline.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/perfMemory.hpp"
-#include "services/memTracker.hpp"
-#include "utilities/exceptions.hpp"
-
-// put OS-includes here
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* For POSIX-compliant getpwuid_r on Solaris */
-#define _POSIX_PTHREAD_SEMANTICS
-#include
-
-static char* backing_store_file_name = NULL; // name of the backing store
- // file, if successfully created.
-
-// Standard Memory Implementation Details
-
-// create the PerfData memory region in standard memory.
-//
-static char* create_standard_memory(size_t size) {
-
- // allocate an aligned chuck of memory
- char* mapAddress = os::reserve_memory(size);
-
- if (mapAddress == NULL) {
- return NULL;
- }
-
- // commit memory
- if (!os::commit_memory(mapAddress, size, !ExecMem)) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not commit PerfData memory\n");
- }
- os::release_memory(mapAddress, size);
- return NULL;
- }
-
- return mapAddress;
-}
-
-// delete the PerfData memory region
-//
-static void delete_standard_memory(char* addr, size_t size) {
-
- // there are no persistent external resources to cleanup for standard
- // memory. since DestroyJavaVM does not support unloading of the JVM,
- // cleanup of the memory resource is not performed. The memory will be
- // reclaimed by the OS upon termination of the process.
- //
- return;
-}
-
-// save the specified memory region to the given file
-//
-// Note: this function might be called from signal handler (by os::abort()),
-// don't allocate heap memory.
-//
-static void save_memory_to_file(char* addr, size_t size) {
-
- const char* destfile = PerfMemory::get_perfdata_file_path();
- assert(destfile[0] != '\0', "invalid PerfData file path");
-
- int result;
-
- RESTARTABLE(::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE),
- result);;
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not create Perfdata save file: %s: %s\n",
- destfile, os::strerror(errno));
- }
- } else {
-
- int fd = result;
-
- for (size_t remaining = size; remaining > 0;) {
-
- RESTARTABLE(::write(fd, addr, remaining), result);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("Could not write Perfdata save file: %s: %s\n",
- destfile, os::strerror(errno));
- }
- break;
- }
- remaining -= (size_t)result;
- addr += result;
- }
-
- result = ::close(fd);
- if (PrintMiscellaneous && Verbose) {
- if (result == OS_ERR) {
- warning("Could not close %s: %s\n", destfile, os::strerror(errno));
- }
- }
- }
- FREE_C_HEAP_ARRAY(char, destfile);
-}
-
-
-// Shared Memory Implementation Details
-
-// Note: the solaris and linux shared memory implementation uses the mmap
-// interface with a backing store file to implement named shared memory.
-// Using the file system as the name space for shared memory allows a
-// common name space to be supported across a variety of platforms. It
-// also provides a name space that Java applications can deal with through
-// simple file apis.
-//
-// The solaris and linux implementations store the backing store file in
-// a user specific temporary directory located in the /tmp file system,
-// which is always a local file system and is sometimes a RAM based file
-// system.
-
-// return the user specific temporary directory name.
-//
-// the caller is expected to free the allocated memory.
-//
-static char* get_user_tmp_dir(const char* user) {
-
- const char* tmpdir = os::get_temp_directory();
- const char* perfdir = PERFDATA_NAME;
- size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3;
- char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
-
- // construct the path name to user specific tmp directory
- snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user);
-
- return dirname;
-}
-
-// convert the given file name into a process id. if the file
-// does not meet the file naming constraints, return 0.
-//
-static pid_t filename_to_pid(const char* filename) {
-
- // a filename that doesn't begin with a digit is not a
- // candidate for conversion.
- //
- if (!isdigit(*filename)) {
- return 0;
- }
-
- // check if file name can be converted to an integer without
- // any leftover characters.
- //
- char* remainder = NULL;
- errno = 0;
- pid_t pid = (pid_t)strtol(filename, &remainder, 10);
-
- if (errno != 0) {
- return 0;
- }
-
- // check for left over characters. If any, then the filename is
- // not a candidate for conversion.
- //
- if (remainder != NULL && *remainder != '\0') {
- return 0;
- }
-
- // successful conversion, return the pid
- return pid;
-}
-
-
-// Check if the given statbuf is considered a secure directory for
-// the backing store files. Returns true if the directory is considered
-// a secure location. Returns false if the statbuf is a symbolic link or
-// if an error occurred.
-//
-static bool is_statbuf_secure(struct stat *statp) {
- if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) {
- // The path represents a link or some non-directory file type,
- // which is not what we expected. Declare it insecure.
- //
- return false;
- }
- // We have an existing directory, check if the permissions are safe.
- //
- if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) {
- // The directory is open for writing and could be subjected
- // to a symlink or a hard link attack. Declare it insecure.
- //
- return false;
- }
- // If user is not root then see if the uid of the directory matches the effective uid of the process.
- uid_t euid = geteuid();
- if ((euid != 0) && (statp->st_uid != euid)) {
- // The directory was not created by this user, declare it insecure.
- //
- return false;
- }
- return true;
-}
-
-
-// Check if the given path is considered a secure directory for
-// the backing store files. Returns true if the directory exists
-// and is considered a secure location. Returns false if the path
-// is a symbolic link or if an error occurred.
-//
-static bool is_directory_secure(const char* path) {
- struct stat statbuf;
- int result = 0;
-
- RESTARTABLE(::lstat(path, &statbuf), result);
- if (result == OS_ERR) {
- return false;
- }
-
- // The path exists, see if it is secure.
- return is_statbuf_secure(&statbuf);
-}
-
-
-// Check if the given directory file descriptor is considered a secure
-// directory for the backing store files. Returns true if the directory
-// exists and is considered a secure location. Returns false if the path
-// is a symbolic link or if an error occurred.
-//
-static bool is_dirfd_secure(int dir_fd) {
- struct stat statbuf;
- int result = 0;
-
- RESTARTABLE(::fstat(dir_fd, &statbuf), result);
- if (result == OS_ERR) {
- return false;
- }
-
- // The path exists, now check its mode.
- return is_statbuf_secure(&statbuf);
-}
-
-
-// Check to make sure fd1 and fd2 are referencing the same file system object.
-//
-static bool is_same_fsobject(int fd1, int fd2) {
- struct stat statbuf1;
- struct stat statbuf2;
- int result = 0;
-
- RESTARTABLE(::fstat(fd1, &statbuf1), result);
- if (result == OS_ERR) {
- return false;
- }
- RESTARTABLE(::fstat(fd2, &statbuf2), result);
- if (result == OS_ERR) {
- return false;
- }
-
- if ((statbuf1.st_ino == statbuf2.st_ino) &&
- (statbuf1.st_dev == statbuf2.st_dev)) {
- return true;
- } else {
- return false;
- }
-}
-
-
-// Open the directory of the given path and validate it.
-// Return a DIR * of the open directory.
-//
-static DIR *open_directory_secure(const char* dirname) {
- // Open the directory using open() so that it can be verified
- // to be secure by calling is_dirfd_secure(), opendir() and then check
- // to see if they are the same file system object. This method does not
- // introduce a window of opportunity for the directory to be attacked that
- // calling opendir() and is_directory_secure() does.
- int result;
- DIR *dirp = NULL;
- RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result);
- if (result == OS_ERR) {
- // Directory doesn't exist or is a symlink, so there is nothing to cleanup.
- if (PrintMiscellaneous && Verbose) {
- if (errno == ELOOP) {
- warning("directory %s is a symlink and is not secure\n", dirname);
- } else {
- warning("could not open directory %s: %s\n", dirname, os::strerror(errno));
- }
- }
- return dirp;
- }
- int fd = result;
-
- // Determine if the open directory is secure.
- if (!is_dirfd_secure(fd)) {
- // The directory is not a secure directory.
- os::close(fd);
- return dirp;
- }
-
- // Open the directory.
- dirp = ::opendir(dirname);
- if (dirp == NULL) {
- // The directory doesn't exist, close fd and return.
- os::close(fd);
- return dirp;
- }
-
- // Check to make sure fd and dirp are referencing the same file system object.
- if (!is_same_fsobject(fd, dirp->d_fd)) {
- // The directory is not secure.
- os::close(fd);
- os::closedir(dirp);
- dirp = NULL;
- return dirp;
- }
-
- // Close initial open now that we know directory is secure
- os::close(fd);
-
- return dirp;
-}
-
-// NOTE: The code below uses fchdir(), open() and unlink() because
-// fdopendir(), openat() and unlinkat() are not supported on all
-// versions. Once the support for fdopendir(), openat() and unlinkat()
-// is available on all supported versions the code can be changed
-// to use these functions.
-
-// Open the directory of the given path, validate it and set the
-// current working directory to it.
-// Return a DIR * of the open directory and the saved cwd fd.
-//
-static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
-
- // Open the directory.
- DIR* dirp = open_directory_secure(dirname);
- if (dirp == NULL) {
- // Directory doesn't exist or is insecure, so there is nothing to cleanup.
- return dirp;
- }
- int fd = dirp->d_fd;
-
- // Open a fd to the cwd and save it off.
- int result;
- RESTARTABLE(::open(".", O_RDONLY), result);
- if (result == OS_ERR) {
- *saved_cwd_fd = -1;
- } else {
- *saved_cwd_fd = result;
- }
-
- // Set the current directory to dirname by using the fd of the directory and
- // handle errors, otherwise shared memory files will be created in cwd.
- result = fchdir(fd);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("could not change to directory %s", dirname);
- }
- if (*saved_cwd_fd != -1) {
- ::close(*saved_cwd_fd);
- *saved_cwd_fd = -1;
- }
- // Close the directory.
- os::closedir(dirp);
- return NULL;
- } else {
- return dirp;
- }
-}
-
-// Close the directory and restore the current working directory.
-//
-static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
-
- int result;
- // If we have a saved cwd change back to it and close the fd.
- if (saved_cwd_fd != -1) {
- result = fchdir(saved_cwd_fd);
- ::close(saved_cwd_fd);
- }
-
- // Close the directory.
- os::closedir(dirp);
-}
-
-// Check if the given file descriptor is considered a secure.
-//
-static bool is_file_secure(int fd, const char *filename) {
-
- int result;
- struct stat statbuf;
-
- // Determine if the file is secure.
- RESTARTABLE(::fstat(fd, &statbuf), result);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("fstat failed on %s: %s\n", filename, os::strerror(errno));
- }
- return false;
- }
- if (statbuf.st_nlink > 1) {
- // A file with multiple links is not expected.
- if (PrintMiscellaneous && Verbose) {
- warning("file %s has multiple links\n", filename);
- }
- return false;
- }
- return true;
-}
-
-// return the user name for the given user id
-//
-// the caller is expected to free the allocated memory.
-//
-static char* get_user_name(uid_t uid) {
-
- struct passwd pwent;
-
- // determine the max pwbuf size from sysconf, and hardcode
- // a default if this not available through sysconf.
- //
- long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
- if (bufsize == -1)
- bufsize = 1024;
-
- char* pwbuf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
-
- struct passwd* p = NULL;
- int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p);
-
- if (p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {
- if (PrintMiscellaneous && Verbose) {
- if (p == NULL) {
- warning("Could not retrieve passwd entry: %s\n",
- os::strerror(errno));
- }
- else {
- warning("Could not determine user name: %s\n",
- p->pw_name == NULL ? "pw_name = NULL" :
- "pw_name zero length");
- }
- }
- FREE_C_HEAP_ARRAY(char, pwbuf);
- return NULL;
- }
-
- char* user_name = NEW_C_HEAP_ARRAY(char, strlen(p->pw_name) + 1, mtInternal);
- strcpy(user_name, p->pw_name);
-
- FREE_C_HEAP_ARRAY(char, pwbuf);
- return user_name;
-}
-
-// return the name of the user that owns the process identified by vmid.
-//
-// This method uses a slow directory search algorithm to find the backing
-// store file for the specified vmid and returns the user name, as determined
-// by the user name suffix of the hsperfdata_ directory name.
-//
-// the caller is expected to free the allocated memory.
-//
-static char* get_user_name_slow(int vmid, TRAPS) {
-
- // short circuit the directory search if the process doesn't even exist.
- if (kill(vmid, 0) == OS_ERR) {
- if (errno == ESRCH) {
- THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
- "Process not found");
- }
- else /* EPERM */ {
- THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno));
- }
- }
-
- // directory search
- char* oldest_user = NULL;
- time_t oldest_ctime = 0;
-
- const char* tmpdirname = os::get_temp_directory();
-
- // open the temp directory
- DIR* tmpdirp = os::opendir(tmpdirname);
-
- if (tmpdirp == NULL) {
- // Cannot open the directory to get the user name, return.
- return NULL;
- }
-
- // for each entry in the directory that matches the pattern hsperfdata_*,
- // open the directory and check if the file for the given vmid exists.
- // The file with the expected name and the latest creation date is used
- // to determine the user name for the process id.
- //
- struct dirent* dentry;
- errno = 0;
- while ((dentry = os::readdir(tmpdirp)) != NULL) {
-
- // check if the directory entry is a hsperfdata file
- if (strncmp(dentry->d_name, PERFDATA_NAME, strlen(PERFDATA_NAME)) != 0) {
- continue;
- }
-
- char* usrdir_name = NEW_C_HEAP_ARRAY(char,
- strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal);
- strcpy(usrdir_name, tmpdirname);
- strcat(usrdir_name, "/");
- strcat(usrdir_name, dentry->d_name);
-
- // open the user directory
- DIR* subdirp = open_directory_secure(usrdir_name);
-
- if (subdirp == NULL) {
- FREE_C_HEAP_ARRAY(char, usrdir_name);
- continue;
- }
-
- // Since we don't create the backing store files in directories
- // pointed to by symbolic links, we also don't follow them when
- // looking for the files. We check for a symbolic link after the
- // call to opendir in order to eliminate a small window where the
- // symlink can be exploited.
- //
- if (!is_directory_secure(usrdir_name)) {
- FREE_C_HEAP_ARRAY(char, usrdir_name);
- os::closedir(subdirp);
- continue;
- }
-
- struct dirent* udentry;
- errno = 0;
- while ((udentry = os::readdir(subdirp)) != NULL) {
-
- if (filename_to_pid(udentry->d_name) == vmid) {
- struct stat statbuf;
- int result;
-
- char* filename = NEW_C_HEAP_ARRAY(char,
- strlen(usrdir_name) + strlen(udentry->d_name) + 2, mtInternal);
-
- strcpy(filename, usrdir_name);
- strcat(filename, "/");
- strcat(filename, udentry->d_name);
-
- // don't follow symbolic links for the file
- RESTARTABLE(::lstat(filename, &statbuf), result);
- if (result == OS_ERR) {
- FREE_C_HEAP_ARRAY(char, filename);
- continue;
- }
-
- // skip over files that are not regular files.
- if (!S_ISREG(statbuf.st_mode)) {
- FREE_C_HEAP_ARRAY(char, filename);
- continue;
- }
-
- // compare and save filename with latest creation time
- if (statbuf.st_size > 0 && statbuf.st_ctime > oldest_ctime) {
-
- if (statbuf.st_ctime > oldest_ctime) {
- char* user = strchr(dentry->d_name, '_') + 1;
-
- FREE_C_HEAP_ARRAY(char, oldest_user);
- oldest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal);
-
- strcpy(oldest_user, user);
- oldest_ctime = statbuf.st_ctime;
- }
- }
-
- FREE_C_HEAP_ARRAY(char, filename);
- }
- }
- os::closedir(subdirp);
- FREE_C_HEAP_ARRAY(char, usrdir_name);
- }
- os::closedir(tmpdirp);
-
- return(oldest_user);
-}
-
-// return the name of the user that owns the JVM indicated by the given vmid.
-//
-static char* get_user_name(int vmid, TRAPS) {
-
- char psinfo_name[PATH_MAX];
- int result;
-
- snprintf(psinfo_name, PATH_MAX, "/proc/%d/psinfo", vmid);
-
- RESTARTABLE(::open(psinfo_name, O_RDONLY), result);
-
- if (result != OS_ERR) {
- int fd = result;
-
- psinfo_t psinfo;
- char* addr = (char*)&psinfo;
-
- for (size_t remaining = sizeof(psinfo_t); remaining > 0;) {
-
- RESTARTABLE(::read(fd, addr, remaining), result);
- if (result == OS_ERR) {
- ::close(fd);
- THROW_MSG_0(vmSymbols::java_io_IOException(), "Read error");
- } else {
- remaining-=result;
- addr+=result;
- }
- }
-
- ::close(fd);
-
- // get the user name for the effective user id of the process
- char* user_name = get_user_name(psinfo.pr_euid);
-
- return user_name;
- }
-
- if (result == OS_ERR && errno == EACCES) {
-
- // In this case, the psinfo file for the process id existed,
- // but we didn't have permission to access it.
- THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
- os::strerror(errno));
- }
-
- // at this point, we don't know if the process id itself doesn't
- // exist or if the psinfo file doesn't exit. If the psinfo file
- // doesn't exist, then we are running on Solaris 2.5.1 or earlier.
- // since the structured procfs and old procfs interfaces can't be
- // mixed, we attempt to find the file through a directory search.
-
- return get_user_name_slow(vmid, THREAD);
-}
-
-// return the file name of the backing store file for the named
-// shared memory region for the given user name and vmid.
-//
-// the caller is expected to free the allocated memory.
-//
-static char* get_sharedmem_filename(const char* dirname, int vmid) {
-
- // add 2 for the file separator and a NULL terminator.
- size_t nbytes = strlen(dirname) + UINT_CHARS + 2;
-
- char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
- snprintf(name, nbytes, "%s/%d", dirname, vmid);
-
- return name;
-}
-
-
-// remove file
-//
-// this method removes the file specified by the given path
-//
-static void remove_file(const char* path) {
-
- int result;
-
- // if the file is a directory, the following unlink will fail. since
- // we don't expect to find directories in the user temp directory, we
- // won't try to handle this situation. even if accidentially or
- // maliciously planted, the directory's presence won't hurt anything.
- //
- RESTARTABLE(::unlink(path), result);
- if (PrintMiscellaneous && Verbose && result == OS_ERR) {
- if (errno != ENOENT) {
- warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, os::strerror(errno));
- }
- }
-}
-
-
-// cleanup stale shared memory resources
-//
-// This method attempts to remove all stale shared memory files in
-// the named user temporary directory. It scans the named directory
-// for files matching the pattern ^$[0-9]*$. For each file found, the
-// process id is extracted from the file name and a test is run to
-// determine if the process is alive. If the process is not alive,
-// any stale file resources are removed.
-//
-static void cleanup_sharedmem_resources(const char* dirname) {
-
- int saved_cwd_fd;
- // open the directory
- DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
- if (dirp == NULL) {
- // directory doesn't exist or is insecure, so there is nothing to cleanup
- return;
- }
-
- // for each entry in the directory that matches the expected file
- // name pattern, determine if the file resources are stale and if
- // so, remove the file resources. Note, instrumented HotSpot processes
- // for this user may start and/or terminate during this search and
- // remove or create new files in this directory. The behavior of this
- // loop under these conditions is dependent upon the implementation of
- // opendir/readdir.
- //
- struct dirent* entry;
- errno = 0;
- while ((entry = os::readdir(dirp)) != NULL) {
-
- pid_t pid = filename_to_pid(entry->d_name);
-
- if (pid == 0) {
-
- if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
-
- // attempt to remove all unexpected files, except "." and ".."
- unlink(entry->d_name);
- }
-
- errno = 0;
- continue;
- }
-
- // we now have a file name that converts to a valid integer
- // that could represent a process id . if this process id
- // matches the current process id or the process is not running,
- // then remove the stale file resources.
- //
- // process liveness is detected by sending signal number 0 to
- // the process id (see kill(2)). if kill determines that the
- // process does not exist, then the file resources are removed.
- // if kill determines that that we don't have permission to
- // signal the process, then the file resources are assumed to
- // be stale and are removed because the resources for such a
- // process should be in a different user specific directory.
- //
- if ((pid == os::current_process_id()) ||
- (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
-
- unlink(entry->d_name);
- }
- errno = 0;
- }
-
- // close the directory and reset the current working directory
- close_directory_secure_cwd(dirp, saved_cwd_fd);
-}
-
-// make the user specific temporary directory. Returns true if
-// the directory exists and is secure upon return. Returns false
-// if the directory exists but is either a symlink, is otherwise
-// insecure, or if an error occurred.
-//
-static bool make_user_tmp_dir(const char* dirname) {
-
- // create the directory with 0755 permissions. note that the directory
- // will be owned by euid::egid, which may not be the same as uid::gid.
- //
- if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) {
- if (errno == EEXIST) {
- // The directory already exists and was probably created by another
- // JVM instance. However, this could also be the result of a
- // deliberate symlink. Verify that the existing directory is safe.
- //
- if (!is_directory_secure(dirname)) {
- // directory is not secure
- if (PrintMiscellaneous && Verbose) {
- warning("%s directory is insecure\n", dirname);
- }
- return false;
- }
- }
- else {
- // we encountered some other failure while attempting
- // to create the directory
- //
- if (PrintMiscellaneous && Verbose) {
- warning("could not create directory %s: %s\n",
- dirname, os::strerror(errno));
- }
- return false;
- }
- }
- return true;
-}
-
-// create the shared memory file resources
-//
-// This method creates the shared memory file with the given size
-// This method also creates the user specific temporary directory, if
-// it does not yet exist.
-//
-static int create_sharedmem_resources(const char* dirname, const char* filename, size_t size) {
-
- // make the user temporary directory
- if (!make_user_tmp_dir(dirname)) {
- // could not make/find the directory or the found directory
- // was not secure
- return -1;
- }
-
- int saved_cwd_fd;
- // open the directory and set the current working directory to it
- DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
- if (dirp == NULL) {
- // Directory doesn't exist or is insecure, so cannot create shared
- // memory file.
- return -1;
- }
-
- // Open the filename in the current directory.
- // Cannot use O_TRUNC here; truncation of an existing file has to happen
- // after the is_file_secure() check below.
- int result;
- RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- if (errno == ELOOP) {
- warning("file %s is a symlink and is not secure\n", filename);
- } else {
- warning("could not create file %s: %s\n", filename, os::strerror(errno));
- }
- }
- // close the directory and reset the current working directory
- close_directory_secure_cwd(dirp, saved_cwd_fd);
-
- return -1;
- }
- // close the directory and reset the current working directory
- close_directory_secure_cwd(dirp, saved_cwd_fd);
-
- // save the file descriptor
- int fd = result;
-
- // check to see if the file is secure
- if (!is_file_secure(fd, filename)) {
- ::close(fd);
- return -1;
- }
-
- // truncate the file to get rid of any existing data
- RESTARTABLE(::ftruncate(fd, (off_t)0), result);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("could not truncate shared memory file: %s\n", os::strerror(errno));
- }
- ::close(fd);
- return -1;
- }
- // set the file size
- RESTARTABLE(::ftruncate(fd, (off_t)size), result);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("could not set shared memory file size: %s\n", os::strerror(errno));
- }
- ::close(fd);
- return -1;
- }
-
- return fd;
-}
-
-// open the shared memory file for the given user and vmid. returns
-// the file descriptor for the open file or -1 if the file could not
-// be opened.
-//
-static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
-
- // open the file
- int result;
- RESTARTABLE(::open(filename, oflags), result);
- if (result == OS_ERR) {
- if (errno == ENOENT) {
- THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
- "Process not found", OS_ERR);
- }
- else if (errno == EACCES) {
- THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
- "Permission denied", OS_ERR);
- }
- else {
- THROW_MSG_(vmSymbols::java_io_IOException(),
- os::strerror(errno), OS_ERR);
- }
- }
- int fd = result;
-
- // check to see if the file is secure
- if (!is_file_secure(fd, filename)) {
- ::close(fd);
- return -1;
- }
-
- return fd;
-}
-
-// create a named shared memory region. returns the address of the
-// memory region on success or NULL on failure. A return value of
-// NULL will ultimately disable the shared memory feature.
-//
-// On Solaris, the name space for shared memory objects
-// is the file system name space.
-//
-// A monitoring application attaching to a JVM does not need to know
-// the file system name of the shared memory object. However, it may
-// be convenient for applications to discover the existence of newly
-// created and terminating JVMs by watching the file system name space
-// for files being created or removed.
-//
-static char* mmap_create_shared(size_t size) {
-
- int result;
- int fd;
- char* mapAddress;
-
- int vmid = os::current_process_id();
-
- char* user_name = get_user_name(geteuid());
-
- if (user_name == NULL)
- return NULL;
-
- char* dirname = get_user_tmp_dir(user_name);
- char* filename = get_sharedmem_filename(dirname, vmid);
-
- // get the short filename
- char* short_filename = strrchr(filename, '/');
- if (short_filename == NULL) {
- short_filename = filename;
- } else {
- short_filename++;
- }
-
- // cleanup any stale shared memory files
- cleanup_sharedmem_resources(dirname);
-
- assert(((size > 0) && (size % os::vm_page_size() == 0)),
- "unexpected PerfMemory region size");
-
- fd = create_sharedmem_resources(dirname, short_filename, size);
-
- FREE_C_HEAP_ARRAY(char, user_name);
- FREE_C_HEAP_ARRAY(char, dirname);
-
- if (fd == -1) {
- FREE_C_HEAP_ARRAY(char, filename);
- return NULL;
- }
-
- mapAddress = (char*)::mmap((char*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-
- result = ::close(fd);
- assert(result != OS_ERR, "could not close file");
-
- if (mapAddress == MAP_FAILED) {
- if (PrintMiscellaneous && Verbose) {
- warning("mmap failed - %s\n", os::strerror(errno));
- }
- remove_file(filename);
- FREE_C_HEAP_ARRAY(char, filename);
- return NULL;
- }
-
- // save the file name for use in delete_shared_memory()
- backing_store_file_name = filename;
-
- // clear the shared memory region
- (void)::memset((void*) mapAddress, 0, size);
-
- // it does not go through os api, the operation has to record from here
- MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress,
- size, CURRENT_PC, mtInternal);
-
- return mapAddress;
-}
-
-// release a named shared memory region
-//
-static void unmap_shared(char* addr, size_t bytes) {
- os::release_memory(addr, bytes);
-}
-
-// create the PerfData memory region in shared memory.
-//
-static char* create_shared_memory(size_t size) {
-
- // create the shared memory region.
- return mmap_create_shared(size);
-}
-
-// delete the shared PerfData memory region
-//
-static void delete_shared_memory(char* addr, size_t size) {
-
- // cleanup the persistent shared memory resources. since DestroyJavaVM does
- // not support unloading of the JVM, unmapping of the memory resource is
- // not performed. The memory will be reclaimed by the OS upon termination of
- // the process. The backing store file is deleted from the file system.
-
- assert(!PerfDisableSharedMem, "shouldn't be here");
-
- if (backing_store_file_name != NULL) {
- remove_file(backing_store_file_name);
- // Don't.. Free heap memory could deadlock os::abort() if it is called
- // from signal handler. OS will reclaim the heap memory.
- // FREE_C_HEAP_ARRAY(char, backing_store_file_name);
- backing_store_file_name = NULL;
- }
-}
-
-// return the size of the file for the given file descriptor
-// or 0 if it is not a valid size for a shared memory file
-//
-static size_t sharedmem_filesize(int fd, TRAPS) {
-
- struct stat statbuf;
- int result;
-
- RESTARTABLE(::fstat(fd, &statbuf), result);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("fstat failed: %s\n", os::strerror(errno));
- }
- THROW_MSG_0(vmSymbols::java_io_IOException(),
- "Could not determine PerfMemory size");
- }
-
- if ((statbuf.st_size == 0) ||
- ((size_t)statbuf.st_size % os::vm_page_size() != 0)) {
- THROW_MSG_0(vmSymbols::java_io_IOException(),
- "Invalid PerfMemory size");
- }
-
- return (size_t)statbuf.st_size;
-}
-
-// attach to a named shared memory region.
-//
-static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemoryMode mode, char** addr, size_t* sizep, TRAPS) {
-
- char* mapAddress;
- int result;
- int fd;
- size_t size = 0;
- const char* luser = NULL;
-
- int mmap_prot;
- int file_flags;
-
- ResourceMark rm;
-
- // map the high level access mode to the appropriate permission
- // constructs for the file and the shared memory mapping.
- if (mode == PerfMemory::PERF_MODE_RO) {
- mmap_prot = PROT_READ;
- file_flags = O_RDONLY | O_NOFOLLOW;
- }
- else if (mode == PerfMemory::PERF_MODE_RW) {
-#ifdef LATER
- mmap_prot = PROT_READ | PROT_WRITE;
- file_flags = O_RDWR | O_NOFOLLOW;
-#else
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "Unsupported access mode");
-#endif
- }
- else {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "Illegal access mode");
- }
-
- if (user == NULL || strlen(user) == 0) {
- luser = get_user_name(vmid, CHECK);
- }
- else {
- luser = user;
- }
-
- if (luser == NULL) {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "Could not map vmid to user Name");
- }
-
- char* dirname = get_user_tmp_dir(luser);
-
- // since we don't follow symbolic links when creating the backing
- // store file, we don't follow them when attaching either.
- //
- if (!is_directory_secure(dirname)) {
- FREE_C_HEAP_ARRAY(char, dirname);
- if (luser != user) {
- FREE_C_HEAP_ARRAY(char, luser);
- }
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "Process not found");
- }
-
- char* filename = get_sharedmem_filename(dirname, vmid);
-
- // copy heap memory to resource memory. the open_sharedmem_file
- // method below need to use the filename, but could throw an
- // exception. using a resource array prevents the leak that
- // would otherwise occur.
- char* rfilename = NEW_RESOURCE_ARRAY(char, strlen(filename) + 1);
- strcpy(rfilename, filename);
-
- // free the c heap resources that are no longer needed
- if (luser != user) FREE_C_HEAP_ARRAY(char, luser);
- FREE_C_HEAP_ARRAY(char, dirname);
- FREE_C_HEAP_ARRAY(char, filename);
-
- // open the shared memory file for the give vmid
- fd = open_sharedmem_file(rfilename, file_flags, THREAD);
-
- if (fd == OS_ERR) {
- return;
- }
-
- if (HAS_PENDING_EXCEPTION) {
- ::close(fd);
- return;
- }
-
- if (*sizep == 0) {
- size = sharedmem_filesize(fd, CHECK);
- } else {
- size = *sizep;
- }
-
- assert(size > 0, "unexpected size <= 0");
-
- mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0);
-
- result = ::close(fd);
- assert(result != OS_ERR, "could not close file");
-
- if (mapAddress == MAP_FAILED) {
- if (PrintMiscellaneous && Verbose) {
- warning("mmap failed: %s\n", os::strerror(errno));
- }
- THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
- "Could not map PerfMemory");
- }
-
- // it does not go through os api, the operation has to record from here
- MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress,
- size, CURRENT_PC, mtInternal);
-
- *addr = mapAddress;
- *sizep = size;
-
- log_debug(perf, memops)("mapped " SIZE_FORMAT " bytes for vmid %d at "
- INTPTR_FORMAT, size, vmid, (void*)mapAddress);
-}
-
-// create the PerfData memory region
-//
-// This method creates the memory region used to store performance
-// data for the JVM. The memory may be created in standard or
-// shared memory.
-//
-void PerfMemory::create_memory_region(size_t size) {
-
- if (PerfDisableSharedMem) {
- // do not share the memory for the performance data.
- _start = create_standard_memory(size);
- }
- else {
- _start = create_shared_memory(size);
- if (_start == NULL) {
-
- // creation of the shared memory region failed, attempt
- // to create a contiguous, non-shared memory region instead.
- //
- if (PrintMiscellaneous && Verbose) {
- warning("Reverting to non-shared PerfMemory region.\n");
- }
- PerfDisableSharedMem = true;
- _start = create_standard_memory(size);
- }
- }
-
- if (_start != NULL) _capacity = size;
-
-}
-
-// delete the PerfData memory region
-//
-// This method deletes the memory region used to store performance
-// data for the JVM. The memory region indicated by the
-// tuple will be inaccessible after a call to this method.
-//
-void PerfMemory::delete_memory_region() {
-
- assert((start() != NULL && capacity() > 0), "verify proper state");
-
- // If user specifies PerfDataSaveFile, it will save the performance data
- // to the specified file name no matter whether PerfDataSaveToFile is specified
- // or not. In other word, -XX:PerfDataSaveFile=.. overrides flag
- // -XX:+PerfDataSaveToFile.
- if (PerfDataSaveToFile || PerfDataSaveFile != NULL) {
- save_memory_to_file(start(), capacity());
- }
-
- if (PerfDisableSharedMem) {
- delete_standard_memory(start(), capacity());
- }
- else {
- delete_shared_memory(start(), capacity());
- }
-}
-
-// attach to the PerfData memory region for another JVM
-//
-// This method returns an tuple that points to
-// a memory buffer that is kept reasonably synchronized with
-// the PerfData memory region for the indicated JVM. This
-// buffer may be kept in synchronization via shared memory
-// or some other mechanism that keeps the buffer updated.
-//
-// If the JVM chooses not to support the attachability feature,
-// this method should throw an UnsupportedOperation exception.
-//
-// This implementation utilizes named shared memory to map
-// the indicated process's PerfData memory region into this JVMs
-// address space.
-//
-void PerfMemory::attach(const char* user, int vmid, PerfMemoryMode mode, char** addrp, size_t* sizep, TRAPS) {
-
- if (vmid == 0 || vmid == os::current_process_id()) {
- *addrp = start();
- *sizep = capacity();
- return;
- }
-
- mmap_attach_shared(user, vmid, mode, addrp, sizep, CHECK);
-}
-
-// detach from the PerfData memory region of another JVM
-//
-// This method detaches the PerfData memory region of another
-// JVM, specified as an tuple of a buffer
-// in this process's address space. This method may perform
-// arbitrary actions to accomplish the detachment. The memory
-// region specified by will be inaccessible after
-// a call to this method.
-//
-// If the JVM chooses not to support the attachability feature,
-// this method should throw an UnsupportedOperation exception.
-//
-// This implementation utilizes named shared memory to detach
-// the indicated process's PerfData memory region from this
-// process's address space.
-//
-void PerfMemory::detach(char* addr, size_t bytes, TRAPS) {
-
- assert(addr != 0, "address sanity check");
- assert(bytes > 0, "capacity sanity check");
-
- if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) {
- // prevent accidental detachment of this process's PerfMemory region
- return;
- }
-
- unmap_shared(addr, bytes);
-}
diff --git a/src/hotspot/os/solaris/threadCritical_solaris.cpp b/src/hotspot/os/solaris/threadCritical_solaris.cpp
deleted file mode 100644
index bb2c9e7e875..00000000000
--- a/src/hotspot/os/solaris/threadCritical_solaris.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2001, 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 "runtime/os.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/threadCritical.hpp"
-
-// OS-includes here
-#include
-#include
-
-//
-// See threadCritical.hpp for details of this class.
-//
-// For some reason, we don't do locking until the
-// os::init() call completes. I'm not sure why this
-// is, and have left it that way for now. This should
-// be reviewed later.
-
-static mutex_t global_mut;
-static thread_t global_mut_owner = -1;
-static int global_mut_count = 0;
-
-ThreadCritical::ThreadCritical() {
- if (os::Solaris::synchronization_initialized()) {
- thread_t owner = thr_self();
- if (global_mut_owner != owner) {
- if (os::Solaris::mutex_lock(&global_mut))
- fatal("ThreadCritical::ThreadCritical: mutex_lock failed (%s)",
- os::strerror(errno));
- assert(global_mut_count == 0, "must have clean count");
- assert(global_mut_owner == -1, "must have clean owner");
- }
- global_mut_owner = owner;
- ++global_mut_count;
- } else {
- assert (Threads::number_of_threads() == 0, "valid only during initialization");
- }
-}
-
-ThreadCritical::~ThreadCritical() {
- if (os::Solaris::synchronization_initialized()) {
- assert(global_mut_owner == thr_self(), "must have correct owner");
- assert(global_mut_count > 0, "must have correct count");
- --global_mut_count;
- if (global_mut_count == 0) {
- global_mut_owner = -1;
- if (os::Solaris::mutex_unlock(&global_mut))
- fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", os::strerror(errno));
- }
- } else {
- assert (Threads::number_of_threads() == 0, "valid only during initialization");
- }
-}
diff --git a/src/hotspot/os/solaris/vmStructs_solaris.hpp b/src/hotspot/os/solaris/vmStructs_solaris.hpp
deleted file mode 100644
index 7a64aafc34c..00000000000
--- a/src/hotspot/os/solaris/vmStructs_solaris.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
-#define OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
-
-// These are the OS-specific fields, types and integer
-// constants required by the Serviceability Agent. This file is
-// referenced by vmStructs.cpp.
-
-#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t)
-
-#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- declare_unsigned_integer_type(OSThread::thread_id_t)
-
-#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-
-#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-
-#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function)
-
-#endif // OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
diff --git a/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp b/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp
index ded9e8f400b..dc28242d5f6 100644
--- a/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp
+++ b/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -85,18 +85,7 @@ inline u4 Bytes::swap_u4(u4 x) {
#ifdef AMD64
inline u8 Bytes::swap_u8(u8 x) {
-#ifdef SPARC_WORKS
- // workaround for SunStudio12 CR6615391
- __asm__ __volatile__ (
- "bswapq %0"
- :"=r" (x) // output : register 0 => x
- :"0" (x) // input : x => register 0
- :"0" // clobbered register
- );
- return x;
-#else
return bswap_64(x);
-#endif
}
#else
// Helper function for swap_u8
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 f63bc277e31..69621b8e712 100644
--- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp
+++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp
@@ -283,10 +283,6 @@ address os::current_stack_pointer() {
void *esp;
__asm__("mov %%" SPELL_REG_SP ", %0":"=r"(esp));
return (address) esp;
-#elif defined(SPARC_WORKS)
- void *esp;
- __asm__("mov %%" SPELL_REG_SP ", %0":"=r"(esp));
- return (address) ((char*)esp + sizeof(long)*2);
#else
register void *esp __asm__ (SPELL_REG_SP);
return (address) esp;
@@ -411,7 +407,7 @@ frame os::get_sender_for_C_frame(frame* fr) {
}
intptr_t* _get_previous_fp() {
-#if defined(SPARC_WORKS) || defined(__clang__) || defined(__llvm__)
+#if defined(__clang__) || defined(__llvm__)
intptr_t **ebp;
__asm__("mov %%" SPELL_REG_FP ", %0":"=r"(ebp));
#else
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 0130ddae61a..4c21793f99a 100644
--- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp
+++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp
@@ -90,14 +90,8 @@ char* os::non_memory_address_word() {
// Must never look like an address returned by reserve_memory,
// even in its subfields (as defined by the CPU immediate fields,
// if the CPU splits constants across multiple instructions).
-#ifdef SPARC
- // On SPARC, 0 != %hi(any real address), because there is no
- // allocation in the first 1Kb of the virtual address space.
- return (char *) 0;
-#else
// This is the value for x86; works pretty well for PPC too.
return (char *) -1;
-#endif // SPARC
}
address os::Bsd::ucontext_get_pc(const ucontext_t* uc) {
diff --git a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp
deleted file mode 100644
index 9f5f98982fb..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_SPARC_ATOMIC_LINUX_SPARC_HPP
-#define OS_CPU_LINUX_SPARC_ATOMIC_LINUX_SPARC_HPP
-
-// Implementation of class atomic
-
-template
-struct Atomic::PlatformAdd {
- template
- D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const;
-
- template
- D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const {
- return add_and_fetch(dest, add_value, order) - add_value;
- }
-};
-
-template<>
-template
-inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(4 == sizeof(I));
- STATIC_ASSERT(4 == sizeof(D));
-
- D rv;
- __asm__ volatile(
- "1: \n\t"
- " ld [%2], %%o2\n\t"
- " add %1, %%o2, %%o3\n\t"
- " cas [%2], %%o2, %%o3\n\t"
- " cmp %%o2, %%o3\n\t"
- " bne 1b\n\t"
- " nop\n\t"
- " add %1, %%o2, %0\n\t"
- : "=r" (rv)
- : "r" (add_value), "r" (dest)
- : "memory", "o2", "o3");
- return rv;
-}
-
-template<>
-template
-inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(I));
- STATIC_ASSERT(8 == sizeof(D));
-
- D rv;
- __asm__ volatile(
- "1: \n\t"
- " ldx [%2], %%o2\n\t"
- " add %1, %%o2, %%o3\n\t"
- " casx [%2], %%o2, %%o3\n\t"
- " cmp %%o2, %%o3\n\t"
- " bne %%xcc, 1b\n\t"
- " nop\n\t"
- " add %1, %%o2, %0\n\t"
- : "=r" (rv)
- : "r" (add_value), "r" (dest)
- : "memory", "o2", "o3");
- return rv;
-}
-
-template<>
-template
-inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(4 == sizeof(T));
- T rv = exchange_value;
- __asm__ volatile(
- " swap [%2],%1\n\t"
- : "=r" (rv)
- : "0" (exchange_value) /* we use same register as for return value */, "r" (dest)
- : "memory");
- return rv;
-}
-
-template<>
-template
-inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(T));
- T rv = exchange_value;
- __asm__ volatile(
- "1:\n\t"
- " mov %1, %%o3\n\t"
- " ldx [%2], %%o2\n\t"
- " casx [%2], %%o2, %%o3\n\t"
- " cmp %%o2, %%o3\n\t"
- " bne %%xcc, 1b\n\t"
- " nop\n\t"
- " mov %%o2, %0\n\t"
- : "=r" (rv)
- : "r" (exchange_value), "r" (dest)
- : "memory", "o2", "o3");
- return rv;
-}
-
-// No direct support for cmpxchg of bytes; emulate using int.
-template<>
-struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
-
-template<>
-template
-inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest,
- T compare_value,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(4 == sizeof(T));
- T rv;
- __asm__ volatile(
- " cas [%2], %3, %0"
- : "=r" (rv)
- : "0" (exchange_value), "r" (dest), "r" (compare_value)
- : "memory");
- return rv;
-}
-
-template<>
-template
-inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest,
- T compare_value,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(T));
- T rv;
- __asm__ volatile(
- " casx [%2], %3, %0"
- : "=r" (rv)
- : "0" (exchange_value), "r" (dest), "r" (compare_value)
- : "memory");
- return rv;
-}
-
-#endif // OS_CPU_LINUX_SPARC_ATOMIC_LINUX_SPARC_HPP
diff --git a/src/hotspot/os_cpu/linux_sparc/globals_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/globals_linux_sparc.hpp
deleted file mode 100644
index 39fab0a1def..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/globals_linux_sparc.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_SPARC_GLOBALS_LINUX_SPARC_HPP
-#define OS_CPU_LINUX_SPARC_GLOBALS_LINUX_SPARC_HPP
-
-//
-// Sets the default values for platform dependent flags used by the
-// runtime system. (see globals.hpp)
-//
-
-define_pd_global(size_t, JVMInvokeMethodSlack, 12288);
-
-// Used on 64 bit platforms for UseCompressedOops base address
-define_pd_global(size_t, HeapBaseMinAddress, CONST64(4)*G);
-
-#endif // OS_CPU_LINUX_SPARC_GLOBALS_LINUX_SPARC_HPP
diff --git a/src/hotspot/os_cpu/linux_sparc/linux_sparc.s b/src/hotspot/os_cpu/linux_sparc/linux_sparc.s
deleted file mode 100644
index 33474ecd9c0..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/linux_sparc.s
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute 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.
-#
-
- # Possibilities:
- # -- membar
- # -- CAS (SP + BIAS, G0, G0)
- # -- wr %g0, %asi
-
- .globl SpinPause
- .type SpinPause,@function
- .align 32
-SpinPause:
- retl
- mov %g0, %o0
-
- .globl _Copy_conjoint_jlongs_atomic
- .type _Copy_conjoint_jlongs_atomic,@function
-_Copy_conjoint_jlongs_atomic:
- cmp %o0, %o1
- bleu 4f
- sll %o2, 3, %o4
- ba 2f
- 1:
- subcc %o4, 8, %o4
- std %o2, [%o1]
- add %o0, 8, %o0
- add %o1, 8, %o1
- 2:
- bge,a 1b
- ldd [%o0], %o2
- ba 5f
- nop
- 3:
- std %o2, [%o1+%o4]
- 4:
- subcc %o4, 8, %o4
- bge,a 3b
- ldd [%o0+%o4], %o2
- 5:
- retl
- nop
-
-
- .globl _flush_reg_windows
- .align 32
- _flush_reg_windows:
- ta 0x03
- retl
- mov %fp, %o0
diff --git a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp
deleted file mode 100644
index 1d91b5836f0..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_SPARC_ORDERACCESS_LINUX_SPARC_HPP
-#define OS_CPU_LINUX_SPARC_ORDERACCESS_LINUX_SPARC_HPP
-
-// Included in orderAccess.hpp header file.
-
-// Implementation of class OrderAccess.
-
-// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions
-static inline void compiler_barrier() {
- __asm__ volatile ("" : : : "memory");
-}
-
-// Assume TSO.
-
-inline void OrderAccess::loadload() { compiler_barrier(); }
-inline void OrderAccess::storestore() { compiler_barrier(); }
-inline void OrderAccess::loadstore() { compiler_barrier(); }
-inline void OrderAccess::storeload() { fence(); }
-
-inline void OrderAccess::acquire() { compiler_barrier(); }
-inline void OrderAccess::release() { compiler_barrier(); }
-
-inline void OrderAccess::fence() {
- __asm__ volatile ("membar #StoreLoad" : : : "memory");
-}
-
-inline void OrderAccess::cross_modify_fence() { }
-
-#endif // OS_CPU_LINUX_SPARC_ORDERACCESS_LINUX_SPARC_HPP
diff --git a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp b/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp
deleted file mode 100644
index a646ff01e3f..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-// no precompiled headers
-#include "jvm.h"
-#include "asm/macroAssembler.hpp"
-#include "classfile/classLoader.hpp"
-#include "classfile/systemDictionary.hpp"
-#include "classfile/vmSymbols.hpp"
-#include "code/codeCache.hpp"
-#include "code/icBuffer.hpp"
-#include "code/vtableStubs.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/allocation.inline.hpp"
-#include "nativeInst_sparc.hpp"
-#include "os_share_linux.hpp"
-#include "prims/jniFastGetField.hpp"
-#include "prims/jvm_misc.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/extendedPC.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/java.hpp"
-#include "runtime/javaCalls.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/osThread.hpp"
-#include "runtime/safepointMechanism.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/timer.hpp"
-#include "utilities/debug.hpp"
-#include "utilities/events.hpp"
-#include "utilities/vmError.hpp"
-
-// Linux/Sparc has rather obscure naming of registers in sigcontext
-// different between 32 and 64 bits
-#define SIG_PC(x) ((x)->sigc_regs.tpc)
-#define SIG_NPC(x) ((x)->sigc_regs.tnpc)
-#define SIG_REGS(x) ((x)->sigc_regs)
-
-// those are to reference registers in sigcontext
-enum {
- CON_G0 = 0,
- CON_G1,
- CON_G2,
- CON_G3,
- CON_G4,
- CON_G5,
- CON_G6,
- CON_G7,
- CON_O0,
- CON_O1,
- CON_O2,
- CON_O3,
- CON_O4,
- CON_O5,
- CON_O6,
- CON_O7,
-};
-
-// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
-// currently interrupted by SIGPROF.
-// os::Solaris::fetch_frame_from_ucontext() tries to skip nested
-// signal frames. Currently we don't do that on Linux, so it's the
-// same as os::fetch_frame_from_context().
-ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread,
- const ucontext_t* uc,
- intptr_t** ret_sp,
- intptr_t** ret_fp) {
- assert(thread != NULL, "just checking");
- assert(ret_sp != NULL, "just checking");
- assert(ret_fp != NULL, "just checking");
-
- return os::fetch_frame_from_context(uc, ret_sp, ret_fp);
-}
-
-ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
- intptr_t** ret_sp,
- intptr_t** ret_fp) {
- const ucontext_t* uc = (const ucontext_t*) ucVoid;
- ExtendedPC epc;
-
- if (uc != NULL) {
- epc = ExtendedPC(os::Linux::ucontext_get_pc(uc));
- if (ret_sp) {
- *ret_sp = os::Linux::ucontext_get_sp(uc);
- }
- if (ret_fp) {
- *ret_fp = (intptr_t*)NULL;
- }
- } else {
- // construct empty ExtendedPC for return value checking
- epc = ExtendedPC(NULL);
- if (ret_sp) {
- *ret_sp = (intptr_t*) NULL;
- }
- if (ret_fp) {
- *ret_fp = (intptr_t*) NULL;
- }
- }
-
- return epc;
-}
-
-frame os::fetch_frame_from_context(const void* ucVoid) {
- intptr_t* sp;
- ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, NULL);
- return frame(sp, frame::unpatchable, epc.pc());
-}
-
-frame os::get_sender_for_C_frame(frame* fr) {
- return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc());
-}
-
-frame os::current_frame() {
- intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()();
- frame myframe(sp, frame::unpatchable,
- CAST_FROM_FN_PTR(address, os::current_frame));
- if (os::is_first_C_frame(&myframe)) {
- // stack is not walkable
- return frame(NULL, frame::unpatchable, NULL);
- } else {
- return os::get_sender_for_C_frame(&myframe);
- }
-}
-
-address os::current_stack_pointer() {
- register void *sp __asm__ ("sp");
- return (address)sp;
-}
-
-char* os::non_memory_address_word() {
- // Must never look like an address returned by reserve_memory,
- // even in its subfields (as defined by the CPU immediate fields,
- // if the CPU splits constants across multiple instructions).
- // On SPARC, 0 != %hi(any real address), because there is no
- // allocation in the first 1Kb of the virtual address space.
- return (char*) 0;
-}
-
-void os::print_context(outputStream *st, const void *context) {
- if (context == NULL) return;
-
- const ucontext_t* uc = (const ucontext_t*)context;
- sigcontext* sc = (sigcontext*)context;
- st->print_cr("Registers:");
-
- st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT
- " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT,
- SIG_REGS(sc).u_regs[CON_G1],
- SIG_REGS(sc).u_regs[CON_G2],
- SIG_REGS(sc).u_regs[CON_G3],
- SIG_REGS(sc).u_regs[CON_G4]);
- st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT
- " G7=" INTPTR_FORMAT " Y=0x%x",
- SIG_REGS(sc).u_regs[CON_G5],
- SIG_REGS(sc).u_regs[CON_G6],
- SIG_REGS(sc).u_regs[CON_G7],
- SIG_REGS(sc).y);
- st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT
- " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT,
- SIG_REGS(sc).u_regs[CON_O0],
- SIG_REGS(sc).u_regs[CON_O1],
- SIG_REGS(sc).u_regs[CON_O2],
- SIG_REGS(sc).u_regs[CON_O3]);
- st->print_cr(" O4=" INTPTR_FORMAT " O5=" INTPTR_FORMAT
- " O6=" INTPTR_FORMAT " O7=" INTPTR_FORMAT,
- SIG_REGS(sc).u_regs[CON_O4],
- SIG_REGS(sc).u_regs[CON_O5],
- SIG_REGS(sc).u_regs[CON_O6],
- SIG_REGS(sc).u_regs[CON_O7]);
-
-
- intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
- st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT
- " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT,
- sp[L0->sp_offset_in_saved_window()],
- sp[L1->sp_offset_in_saved_window()],
- sp[L2->sp_offset_in_saved_window()],
- sp[L3->sp_offset_in_saved_window()]);
- st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT
- " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT,
- sp[L4->sp_offset_in_saved_window()],
- sp[L5->sp_offset_in_saved_window()],
- sp[L6->sp_offset_in_saved_window()],
- sp[L7->sp_offset_in_saved_window()]);
- st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT
- " I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT,
- sp[I0->sp_offset_in_saved_window()],
- sp[I1->sp_offset_in_saved_window()],
- sp[I2->sp_offset_in_saved_window()],
- sp[I3->sp_offset_in_saved_window()]);
- st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT
- " I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT,
- sp[I4->sp_offset_in_saved_window()],
- sp[I5->sp_offset_in_saved_window()],
- sp[I6->sp_offset_in_saved_window()],
- sp[I7->sp_offset_in_saved_window()]);
-
- st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT,
- SIG_PC(sc),
- SIG_NPC(sc));
- st->cr();
- st->cr();
-
- st->print_cr("Top of Stack: (sp=" INTPTR_FORMAT ")", p2i(sp));
- print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t));
- st->cr();
-
- // Note: it may be unsafe to inspect memory near pc. For example, pc may
- // point to garbage if entry point in an nmethod is corrupted. Leave
- // this at the end, and hope for the best.
- address pc = os::Linux::ucontext_get_pc(uc);
- print_instructions(st, pc, sizeof(char));
- st->cr();
-}
-
-
-void os::print_register_info(outputStream *st, const void *context) {
- if (context == NULL) return;
-
- const ucontext_t *uc = (const ucontext_t*)context;
- const sigcontext* sc = (const sigcontext*)context;
- intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc);
-
- st->print_cr("Register to memory mapping:");
- st->cr();
-
- // this is only for the "general purpose" registers
- st->print("G1="); print_location(st, SIG_REGS(sc).u_regs[CON_G1]);
- st->print("G2="); print_location(st, SIG_REGS(sc).u_regs[CON_G2]);
- st->print("G3="); print_location(st, SIG_REGS(sc).u_regs[CON_G3]);
- st->print("G4="); print_location(st, SIG_REGS(sc).u_regs[CON_G4]);
- st->print("G5="); print_location(st, SIG_REGS(sc).u_regs[CON_G5]);
- st->print("G6="); print_location(st, SIG_REGS(sc).u_regs[CON_G6]);
- st->print("G7="); print_location(st, SIG_REGS(sc).u_regs[CON_G7]);
- st->cr();
-
- st->print("O0="); print_location(st, SIG_REGS(sc).u_regs[CON_O0]);
- st->print("O1="); print_location(st, SIG_REGS(sc).u_regs[CON_O1]);
- st->print("O2="); print_location(st, SIG_REGS(sc).u_regs[CON_O2]);
- st->print("O3="); print_location(st, SIG_REGS(sc).u_regs[CON_O3]);
- st->print("O4="); print_location(st, SIG_REGS(sc).u_regs[CON_O4]);
- st->print("O5="); print_location(st, SIG_REGS(sc).u_regs[CON_O5]);
- st->print("O6="); print_location(st, SIG_REGS(sc).u_regs[CON_O6]);
- st->print("O7="); print_location(st, SIG_REGS(sc).u_regs[CON_O7]);
- st->cr();
-
- st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]);
- st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]);
- st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]);
- st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]);
- st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]);
- st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]);
- st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]);
- st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]);
- st->cr();
-
- st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]);
- st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]);
- st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]);
- st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]);
- st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]);
- st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]);
- st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]);
- st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]);
- st->cr();
-}
-
-
-address os::Linux::ucontext_get_pc(const ucontext_t* uc) {
- return (address) SIG_PC((sigcontext*)uc);
-}
-
-void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) {
- sigcontext* ctx = (sigcontext*) uc;
- SIG_PC(ctx) = (intptr_t)pc;
- SIG_NPC(ctx) = (intptr_t)(pc+4);
-}
-
-intptr_t* os::Linux::ucontext_get_sp(const ucontext_t *uc) {
- return (intptr_t*)
- ((intptr_t)SIG_REGS((sigcontext*)uc).u_regs[CON_O6] + STACK_BIAS);
-}
-
-// not used on Sparc
-intptr_t* os::Linux::ucontext_get_fp(const ucontext_t *uc) {
- ShouldNotReachHere();
- return NULL;
-}
-
-// Utility functions
-
-inline static bool checkPrefetch(sigcontext* uc, address pc) {
- if (StubRoutines::is_safefetch_fault(pc)) {
- os::Linux::ucontext_set_pc((ucontext_t*)uc, StubRoutines::continuation_for_safefetch_fault(pc));
- return true;
- }
- return false;
-}
-
-inline static bool checkOverflow(sigcontext* uc,
- address pc,
- address addr,
- JavaThread* thread,
- address* stub) {
- // check if fault address is within thread stack
- if (thread->is_in_full_stack(addr)) {
- // stack overflow
- if (thread->in_stack_yellow_reserved_zone(addr)) {
- thread->disable_stack_yellow_reserved_zone();
- if (thread->thread_state() == _thread_in_Java) {
- // Throw a stack overflow exception. Guard pages will be reenabled
- // while unwinding the stack.
- *stub =
- SharedRuntime::continuation_for_implicit_exception(thread,
- pc,
- SharedRuntime::STACK_OVERFLOW);
- } else {
- // Thread was in the vm or native code. Return and try to finish.
- return true;
- }
- } else if (thread->in_stack_red_zone(addr)) {
- // Fatal red zone violation. Disable the guard pages and fall through
- // to handle_unexpected_exception way down below.
- thread->disable_stack_red_zone();
- tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
-
- // This is a likely cause, but hard to verify. Let's just print
- // it as a hint.
- tty->print_raw_cr("Please check if any of your loaded .so files has "
- "enabled executable stack (see man page execstack(8))");
- } else {
- // Accessing stack address below sp may cause SEGV if current
- // thread has MAP_GROWSDOWN stack. This should only happen when
- // current thread was created by user code with MAP_GROWSDOWN flag
- // and then attached to VM. See notes in os_linux.cpp.
- if (thread->osthread()->expanding_stack() == 0) {
- thread->osthread()->set_expanding_stack();
- if (os::Linux::manually_expand_stack(thread, addr)) {
- thread->osthread()->clear_expanding_stack();
- return true;
- }
- thread->osthread()->clear_expanding_stack();
- } else {
- fatal("recursive segv. expanding stack.");
- }
- }
- }
- return false;
-}
-
-inline static bool checkPollingPage(address pc, address fault, address* stub) {
- if (SafepointMechanism::is_poll_address(fault)) {
- *stub = SharedRuntime::get_poll_stub(pc);
- return true;
- }
- return false;
-}
-
-inline static bool checkByteBuffer(address pc, address npc, JavaThread * thread, address* stub) {
- // BugId 4454115: A read from a MappedByteBuffer can fault
- // here if the underlying file has been truncated.
- // Do not crash the VM in such a case.
- CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
- CompiledMethod* nm = cb->as_compiled_method_or_null();
- bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc));
- if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) {
- if (is_unsafe_arraycopy) {
- npc = UnsafeCopyMemory::page_error_continue_pc(pc);
- }
- *stub = SharedRuntime::handle_unsafe_access(thread, npc);
- return true;
- }
- return false;
-}
-
-inline static bool checkVerifyOops(address pc, address fault, address* stub) {
- if (pc >= MacroAssembler::_verify_oop_implicit_branch[0]
- && pc < MacroAssembler::_verify_oop_implicit_branch[1] ) {
- *stub = MacroAssembler::_verify_oop_implicit_branch[2];
- warning("fixed up memory fault in +VerifyOops at address "
- INTPTR_FORMAT, p2i(fault));
- return true;
- }
- return false;
-}
-
-inline static bool checkFPFault(address pc, int code,
- JavaThread* thread, address* stub) {
- if (code == FPE_INTDIV || code == FPE_FLTDIV) {
- *stub =
- SharedRuntime::
- continuation_for_implicit_exception(thread,
- pc,
- SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
- return true;
- }
- return false;
-}
-
-inline static bool checkNullPointer(address pc, void* fault,
- JavaThread* thread, address* stub) {
- if (MacroAssembler::uses_implicit_null_check(fault)) {
- // Determination of interpreter/vtable stub/compiled code null
- // exception
- *stub =
- SharedRuntime::
- continuation_for_implicit_exception(thread, pc,
- SharedRuntime::IMPLICIT_NULL);
- return true;
- }
- return false;
-}
-
-inline static bool checkFastJNIAccess(address pc, address* stub) {
- address addr = JNI_FastGetField::find_slowcase_pc(pc);
- if (addr != (address)-1) {
- *stub = addr;
- return true;
- }
- return false;
-}
-
-inline static bool checkZombie(sigcontext* uc, address* pc, address* stub) {
- if (nativeInstruction_at(*pc)->is_zombie()) {
- // zombie method (ld [%g0],%o7 instruction)
- *stub = SharedRuntime::get_handle_wrong_method_stub();
-
- // At the stub it needs to look like a call from the caller of this
- // method (not a call from the segv site).
- *pc = (address)SIG_REGS(uc).u_regs[CON_O7];
- return true;
- }
- return false;
-}
-
-inline static bool checkICMiss(sigcontext* uc, address* pc, address* stub) {
-#ifdef COMPILER2
- if (nativeInstruction_at(*pc)->is_ic_miss_trap()) {
-#ifdef ASSERT
-#ifdef TIERED
- CodeBlob* cb = CodeCache::find_blob_unsafe(*pc);
- assert(cb->is_compiled_by_c2(), "Wrong compiler");
-#endif // TIERED
-#endif // ASSERT
- // Inline cache missed and user trap "Tne G0+ST_RESERVED_FOR_USER_0+2" taken.
- *stub = SharedRuntime::get_ic_miss_stub();
- // At the stub it needs to look like a call from the caller of this
- // method (not a call from the segv site).
- *pc = (address)SIG_REGS(uc).u_regs[CON_O7];
- return true;
- }
-#endif // COMPILER2
- return false;
-}
-
-extern "C" JNIEXPORT int
-JVM_handle_linux_signal(int sig,
- siginfo_t* info,
- void* ucVoid,
- int abort_if_unrecognized) {
- // in fact this isn't ucontext_t* at all, but struct sigcontext*
- // but Linux porting layer uses ucontext_t, so to minimize code change
- // we cast as needed
- ucontext_t* ucFake = (ucontext_t*) ucVoid;
- sigcontext* uc = (sigcontext*)ucVoid;
-
- Thread* t = Thread::current_or_null_safe();
-
- // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
- // (no destructors can be run)
- os::ThreadCrashProtection::check_crash_protection(sig, t);
-
- SignalHandlerMark shm(t);
-
- // Note: it's not uncommon that JNI code uses signal/sigset to install
- // then restore certain signal handler (e.g. to temporarily block SIGPIPE,
- // or have a SIGILL handler when detecting CPU type). When that happens,
- // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To
- // avoid unnecessary crash when libjsig is not preloaded, try handle signals
- // that do not require siginfo/ucontext first.
-
- if (sig == SIGPIPE || sig == SIGXFSZ) {
- // allow chained handler to go first
- if (os::Linux::chained_handler(sig, info, ucVoid)) {
- return true;
- } else {
- // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
- return true;
- }
- }
-
-#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
- if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
- if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
- return 1;
- }
- }
-#endif
-
- JavaThread* thread = NULL;
- VMThread* vmthread = NULL;
- if (os::Linux::signal_handlers_are_installed) {
- if (t != NULL ){
- if(t->is_Java_thread()) {
- thread = (JavaThread*)t;
- }
- else if(t->is_VM_thread()){
- vmthread = (VMThread *)t;
- }
- }
- }
-
- // decide if this trap can be handled by a stub
- address stub = NULL;
- address pc = NULL;
- address npc = NULL;
-
- //%note os_trap_1
- if (info != NULL && uc != NULL && thread != NULL) {
- pc = address(SIG_PC(uc));
- npc = address(SIG_NPC(uc));
-
- if (checkPrefetch(uc, pc)) {
- return 1;
- }
-
- // Handle ALL stack overflow variations here
- if (sig == SIGSEGV) {
- if (checkOverflow(uc, pc, (address)info->si_addr, thread, &stub)) {
- return 1;
- }
- }
-
- if (sig == SIGBUS &&
- (thread->thread_state() == _thread_in_vm ||
- thread->thread_state() == _thread_in_native) &&
- thread->doing_unsafe_access()) {
- if (UnsafeCopyMemory::contains_pc(pc)) {
- npc = UnsafeCopyMemory::page_error_continue_pc(pc);
- }
- stub = SharedRuntime::handle_unsafe_access(thread, npc);
- }
-
- if (thread->thread_state() == _thread_in_Java) {
- do {
- // Java thread running in Java code => find exception handler if any
- // a fault inside compiled code, the interpreter, or a stub
-
- if ((sig == SIGSEGV) && checkPollingPage(pc, (address)info->si_addr, &stub)) {
- break;
- }
-
- if ((sig == SIGBUS) && checkByteBuffer(pc, npc, thread, &stub)) {
- break;
- }
-
- if ((sig == SIGSEGV || sig == SIGBUS) &&
- checkVerifyOops(pc, (address)info->si_addr, &stub)) {
- break;
- }
-
- if ((sig == SIGSEGV) && checkZombie(uc, &pc, &stub)) {
- break;
- }
-
- if ((sig == SIGILL) && checkICMiss(uc, &pc, &stub)) {
- break;
- }
-
- if ((sig == SIGFPE) && checkFPFault(pc, info->si_code, thread, &stub)) {
- break;
- }
-
- if ((sig == SIGSEGV) &&
- checkNullPointer(pc, info->si_addr, thread, &stub)) {
- break;
- }
- } while (0);
-
- // jni_fast_GetField can trap at certain pc's if a GC kicks in
- // and the heap gets shrunk before the field access.
- if ((sig == SIGSEGV) || (sig == SIGBUS)) {
- checkFastJNIAccess(pc, &stub);
- }
- }
-
- if (stub != NULL) {
- // save all thread context in case we need to restore it
- thread->set_saved_exception_pc(pc);
- thread->set_saved_exception_npc(npc);
- os::Linux::ucontext_set_pc((ucontext_t*)uc, stub);
- return true;
- }
- }
-
- // signal-chaining
- if (os::Linux::chained_handler(sig, info, ucVoid)) {
- return true;
- }
-
- if (!abort_if_unrecognized) {
- // caller wants another chance, so give it to him
- return false;
- }
-
- if (pc == NULL && uc != NULL) {
- pc = os::Linux::ucontext_get_pc((const ucontext_t*)uc);
- }
-
- // unmask current signal
- sigset_t newset;
- sigemptyset(&newset);
- sigaddset(&newset, sig);
- sigprocmask(SIG_UNBLOCK, &newset, NULL);
-
- VMError::report_and_die(t, sig, pc, info, ucVoid);
-
- ShouldNotReachHere();
- return false;
-}
-
-void os::Linux::init_thread_fpu_state(void) {
- // Nothing to do
-}
-
-int os::Linux::get_fpu_control_word() {
- return 0;
-}
-
-void os::Linux::set_fpu_control_word(int fpu) {
- // nothing
-}
-
-bool os::is_allocatable(size_t bytes) {
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// thread stack
-
-// Minimum usable stack sizes required to get to user code. Space for
-// HotSpot guard pages is added later.
-size_t os::Posix::_compiler_thread_min_stack_allowed = 64 * K;
-size_t os::Posix::_java_thread_min_stack_allowed = 64 * K;
-size_t os::Posix::_vm_internal_thread_min_stack_allowed = 128 * K;
-
-// return default stack size for thr_type
-size_t os::Posix::default_stack_size(os::ThreadType thr_type) {
- // default stack size (compiler thread needs larger stack)
- size_t s = (thr_type == os::compiler_thread ? 4 * M : 1 * M);
- return s;
-}
-
-#ifndef PRODUCT
-void os::verify_stack_alignment() {
-}
-#endif
-
-int os::extra_bang_size_in_bytes() {
- // SPARC does not require the additional stack bang.
- return 0;
-}
diff --git a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.hpp
deleted file mode 100644
index df6fc0b8e75..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_SPARC_OS_LINUX_SPARC_HPP
-#define OS_CPU_LINUX_SPARC_OS_LINUX_SPARC_HPP
-
- //
- // NOTE: we are back in class os here, not Linux
- //
- static int32_t (*atomic_xchg_func) (int32_t, volatile int32_t*);
- static int32_t (*atomic_cmpxchg_func) (int32_t, volatile int32_t*, int32_t);
- static int64_t (*atomic_cmpxchg_long_func)(int64_t, volatile int64_t*, int64_t);
- static int32_t (*atomic_add_func) (int32_t, volatile int32_t*);
-
- static int32_t atomic_xchg_bootstrap (int32_t, volatile int32_t*);
- static int32_t atomic_cmpxchg_bootstrap (int32_t, volatile int32_t*, int32_t);
- static int64_t atomic_cmpxchg_long_bootstrap(int64_t, volatile int64_t*, int64_t);
- static int32_t atomic_add_bootstrap (int32_t, volatile int32_t*);
-
- static void setup_fpu() {}
-
- static bool is_allocatable(size_t bytes);
-
- // Used to register dynamic code cache area with the OS
- // Note: Currently only used in 64 bit Windows implementations
- static bool register_code_area(char *low, char *high) { return true; }
-
-#endif // OS_CPU_LINUX_SPARC_OS_LINUX_SPARC_HPP
diff --git a/src/hotspot/os_cpu/linux_sparc/prefetch_linux_sparc.inline.hpp b/src/hotspot/os_cpu/linux_sparc/prefetch_linux_sparc.inline.hpp
deleted file mode 100644
index e8fc035b838..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/prefetch_linux_sparc.inline.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_SPARC_PREFETCH_LINUX_SPARC_INLINE_HPP
-#define OS_CPU_LINUX_SPARC_PREFETCH_LINUX_SPARC_INLINE_HPP
-
-#include "runtime/prefetch.hpp"
-
-inline void Prefetch::read(void *loc, intx interval) {
- __asm__ volatile("prefetch [%0+%1], 0" : : "r" (loc), "r" (interval) : "memory" );
-}
-
-inline void Prefetch::write(void *loc, intx interval) {
- __asm__ volatile("prefetch [%0+%1], 2" : : "r" (loc), "r" (interval) : "memory" );
-}
-
-#endif // OS_CPU_LINUX_SPARC_PREFETCH_LINUX_SPARC_INLINE_HPP
diff --git a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.cpp b/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.cpp
deleted file mode 100644
index 0d33ce36d15..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "memory/metaspaceShared.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/thread.inline.hpp"
-
-frame JavaThread::pd_last_frame() {
- assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
- assert(_anchor.walkable(), "thread has not dumped its register windows yet");
-
- assert(_anchor.last_Java_pc() != NULL, "Ack no pc!");
- return frame(last_Java_sp(), frame::unpatchable, _anchor.last_Java_pc());
-}
-
-bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
- ucontext_t* uc = (ucontext_t*) ucontext;
- *fr_addr = frame((intptr_t*)uc->uc_mcontext.mc_i7, frame::unpatchable,
- (address)uc->uc_mcontext.mc_gregs[MC_PC]);
- return true;
-}
-
-// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
-// currently interrupted by SIGPROF
-bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
- void* ucontext,
- bool isInJava) {
- assert(Thread::current() == this, "caller must be current thread");
- assert(this->is_Java_thread(), "must be JavaThread");
-
- JavaThread* jt = (JavaThread *)this;
-
- if (!isInJava) {
- // make_walkable flushes register windows and grabs last_Java_pc
- // which can not be done if the ucontext sp matches last_Java_sp
- // stack walking utilities assume last_Java_pc set if marked flushed
- jt->frame_anchor()->make_walkable(jt);
- }
-
- // If we have a walkable last_Java_frame, then we should use it
- // even if isInJava == true. It should be more reliable than
- // ucontext info.
- if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) {
- *fr_addr = jt->pd_last_frame();
- return true;
- }
-
- ucontext_t* uc = (ucontext_t*) ucontext;
-
- // At this point, we don't have a walkable last_Java_frame, so
- // we try to glean some information out of the ucontext.
- intptr_t* ret_sp;
- ExtendedPC addr =
- os::fetch_frame_from_context(uc, &ret_sp,
- NULL /* ret_fp only used on X86 */);
- if (addr.pc() == NULL || ret_sp == NULL) {
- // ucontext wasn't useful
- return false;
- }
-
- if (MetaspaceShared::is_in_trampoline_frame(addr.pc())) {
- // In the middle of a trampoline call. Bail out for safety.
- // This happens rarely so shouldn't affect profiling.
- return false;
- }
-
- // we were running Java code when SIGPROF came in
- if (isInJava) {
- // If we have a last_Java_sp, then the SIGPROF signal caught us
- // right when we were transitioning from _thread_in_Java to a new
- // JavaThreadState. We use last_Java_sp instead of the sp from
- // the ucontext since it should be more reliable.
- if (jt->has_last_Java_frame()) {
- ret_sp = jt->last_Java_sp();
- }
- // Implied else: we don't have a last_Java_sp so we use what we
- // got from the ucontext.
-
- frame ret_frame(ret_sp, frame::unpatchable, addr.pc());
- if (!ret_frame.safe_for_sender(jt)) {
- // nothing else to try if the frame isn't good
- return false;
- }
- *fr_addr = ret_frame;
- return true;
- }
-
- // At this point, we know we weren't running Java code. We might
- // have a last_Java_sp, but we don't have a walkable frame.
- // However, we might still be able to construct something useful
- // if the thread was running native code.
- if (jt->has_last_Java_frame()) {
- assert(!jt->frame_anchor()->walkable(), "case covered above");
-
- if (jt->thread_state() == _thread_in_native) {
- frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc());
- if (!ret_frame.safe_for_sender(jt)) {
- // nothing else to try if the frame isn't good
- return false;
- }
- *fr_addr = ret_frame;
- return true;
- }
- }
-
- // nothing else to try
- return false;
-}
-
-void JavaThread::cache_global_variables() { }
-
diff --git a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp
deleted file mode 100644
index 96ba2ebf865..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP
-#define OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP
-
-private:
-
- void pd_initialize() {
- _anchor.clear();
- _base_of_stack_pointer = NULL;
- }
-
- frame pd_last_frame();
-
- // Sometimes the trap handler needs to record both PC and NPC.
- // This is a SPARC-specific companion to Thread::set_saved_exception_pc.
- address _saved_exception_npc;
-
- // In polling_page_safepoint_handler_blob(s) we have to tail call other
- // blobs without blowing any registers. A tail call requires some
- // register to jump with and we can't blow any registers, so it must
- // be restored in the delay slot. 'restore' cannot be used as it
- // will chop the heads off of 64-bit %o registers in the 32-bit
- // build. Instead we reload the registers using G2_thread and this
- // location. Must be 64bits in the 32-bit LION build.
- jdouble _o_reg_temps[6];
-
- // a stack pointer older than any java frame stack pointer. It is
- // used to validate stack pointers in frame::next_younger_sp (it
- // provides the upper bound in the range check). This is necessary
- // on Solaris/SPARC since the ucontext passed to a signal handler is
- // sometimes corrupt and we need a way to check the extracted sp.
- intptr_t* _base_of_stack_pointer;
-
-public:
-
- static int o_reg_temps_offset_in_bytes() { return offset_of(JavaThread, _o_reg_temps); }
-
-#ifndef _LP64
- address o_reg_temps(int i) { return (address)&_o_reg_temps[i]; }
-#endif
-
- static ByteSize saved_exception_npc_offset() { return byte_offset_of(JavaThread,_saved_exception_npc); }
-
- address saved_exception_npc() { return _saved_exception_npc; }
- void set_saved_exception_npc(address a) { _saved_exception_npc = a; }
-
-
-public:
-
- intptr_t* base_of_stack_pointer() { return _base_of_stack_pointer; }
-
- void set_base_of_stack_pointer(intptr_t* base_sp) {
- _base_of_stack_pointer = base_sp;
- }
-
- void record_base_of_stack_pointer() {
- intptr_t *sp = (intptr_t *)(((intptr_t)StubRoutines::Sparc::flush_callers_register_windows_func()()));
- intptr_t *ysp;
- while((ysp = (intptr_t*)sp[FP->sp_offset_in_saved_window()]) != NULL) {
- sp = (intptr_t *)((intptr_t)ysp + STACK_BIAS);
- }
- _base_of_stack_pointer = sp;
- }
-
- bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
-
- bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava);
-
- // These routines are only used on cpu architectures that
- // have separate register stacks (Itanium).
- static bool register_stack_overflow() { return false; }
- static void enable_register_stack_guard() {}
- static void disable_register_stack_guard() {}
-
-#endif // OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP
diff --git a/src/hotspot/os_cpu/linux_sparc/vmStructs_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/vmStructs_linux_sparc.hpp
deleted file mode 100644
index 380b2aceb52..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/vmStructs_linux_sparc.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_LINUX_SPARC_VMSTRUCTS_LINUX_SPARC_HPP
-#define OS_CPU_LINUX_SPARC_VMSTRUCTS_LINUX_SPARC_HPP
-
-// These are the OS and CPU-specific fields, types and integer
-// constants required by the Serviceability Agent. This file is
-// referenced by vmStructs.cpp.
-
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
- \
- /******************************/ \
- /* Threads (NOTE: incomplete) */ \
- /******************************/ \
- \
- nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t)
-
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
- \
- /**********************/ \
- /* POSIX Thread IDs */ \
- /**********************/ \
- \
- declare_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t)
-
-
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
- \
- /************************/ \
- /* JavaThread constants */ \
- /************************/ \
- \
- declare_constant(JavaFrameAnchor::flushed)
-
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-
-#endif // OS_CPU_LINUX_SPARC_VMSTRUCTS_LINUX_SPARC_HPP
diff --git a/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp b/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp
deleted file mode 100644
index 839e4cfa9c9..00000000000
--- a/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 "logging/log.hpp"
-#include "precompiled.hpp"
-#include "runtime/os.hpp"
-#include "runtime/vm_version.hpp"
-
-
-#define CPUINFO_LINE_SIZE 1024
-
-
-class CPUinfo {
-public:
- CPUinfo(const char* field) : _string(NULL) {
-
- char line[CPUINFO_LINE_SIZE];
- FILE* fp = fopen("/proc/cpuinfo", "r");
-
- if (fp != NULL) {
- while (fgets(line, sizeof(line), fp) != NULL) {
- assert(strlen(line) < sizeof(line) - 1,
- "buffer too small (%d)", CPUINFO_LINE_SIZE);
-
- const char* vstr = match_field(line, field);
-
- if (vstr != NULL) {
- // We have a matching line and a valid starting point to the value of
- // the field, copy the string for keeps.
- _string = strdup(vstr);
- break;
- }
- }
- fclose(fp);
- }
- }
-
- ~CPUinfo() { free((void*)_string); }
-
- const char* value() const { return _string; }
-
- bool valid() const { return _string != NULL; }
-
- bool match(const char* s) const {
- return valid() ? strcmp(_string, s) == 0 : false;
- }
-
-private:
- const char* _string;
-
- const char* match_field(char line[CPUINFO_LINE_SIZE], const char* field);
- const char* match_alo(const char* text, const char* exp);
- const char* match_seq(const char* text, const char* seq);
-};
-
-/* Given a line of text read from /proc/cpuinfo, determine if the property header
- * matches the field specified, according to the following regexp: ""\W+:\W+
- *
- * If we have a matching expression, return a pointer to the first character after
- * the matching pattern, i.e. the "value", otherwise return NULL.
- */
-const char* CPUinfo::match_field(char line[CPUINFO_LINE_SIZE], const char* field) {
- return match_alo(match_seq(match_alo(match_seq(line, field), "\t "), ":"), "\t ");
-}
-
-/* Match a sequence of at-least-one character in the string expression (exp) to
- * the text input.
- */
-const char* CPUinfo::match_alo(const char* text, const char* exp) {
- if (text == NULL) return NULL;
-
- const char* chp;
-
- for (chp = &text[0]; *chp != '\0'; chp++) {
- if (strchr(exp, *chp) == NULL) break;
- }
-
- return text < chp ? chp : NULL;
-}
-
-/* Match an exact sequence of characters as specified by the string expression
- * (seq) to the text input.
- */
-const char* CPUinfo::match_seq(const char* text, const char* seq) {
- if (text == NULL) return NULL;
-
- while (*seq != '\0') {
- if (*seq != *text++) break; else seq++;
- }
-
- return *seq == '\0' ? text : NULL;
-}
-
-
-typedef struct {
- const uint32_t hash;
- bool seen;
- const char* const name;
- const uint64_t mask;
-} FeatureEntry;
-
-
-static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]);
-
-
-void VM_Version::platform_features() {
-
- // Some of the features reported via "cpucaps", such as; 'flush', 'stbar',
- // 'swap', 'muldiv', 'ultra3', 'blkinit', 'n2', 'mul32', 'div32', 'fsmuld'
- // and 'v8plus', are either SPARC V8, supported by all HW or simply nonsense
- // (the 'ultra3' "property").
- //
- // Entries marked as 'NYI' are not yet supported via "cpucaps" but are
- // expected to have the names used in the table below (these are SPARC M7
- // features or more recent).
- //
- // NOTE: Table sorted on lookup/hash ID.
-
- static FeatureEntry s_feature_tbl[] = {
- { 0x006f, false, "v9", ISA_v9_msk }, // Mandatory
- { 0x00a6, false, "md5", ISA_md5_msk },
- { 0x00ce, false, "adi", ISA_adi_msk }, // NYI
- { 0x00d7, false, "ima", ISA_ima_msk },
- { 0x00d9, false, "aes", ISA_aes_msk },
- { 0x00db, false, "hpc", ISA_hpc_msk },
- { 0x00dc, false, "des", ISA_des_msk },
- { 0x00ed, false, "sha1", ISA_sha1_msk },
- { 0x00f2, false, "vis", ISA_vis1_msk },
- { 0x0104, false, "vis2", ISA_vis2_msk },
- { 0x0105, false, "vis3", ISA_vis3_msk },
- { 0x0114, false, "sha512", ISA_sha512_msk },
- { 0x0119, false, "sha256", ISA_sha256_msk },
- { 0x011a, false, "fmaf", ISA_fmaf_msk },
- { 0x0132, false, "popc", ISA_popc_msk },
- { 0x0140, false, "crc32c", ISA_crc32c_msk },
- { 0x0147, false, "vis3b", ISA_vis3b_msk }, // NYI
- { 0x017e, false, "pause", ISA_pause_msk },
- { 0x0182, false, "mwait", ISA_mwait_msk }, // NYI
- { 0x018b, false, "mpmul", ISA_mpmul_msk },
- { 0x018e, false, "sparc5", ISA_sparc5_msk }, // NYI
- { 0x01a9, false, "cbcond", ISA_cbcond_msk },
- { 0x01c3, false, "vamask", ISA_vamask_msk }, // NYI
- { 0x01ca, false, "kasumi", ISA_kasumi_msk },
- { 0x01e3, false, "xmpmul", ISA_xmpmul_msk }, // NYI
- { 0x022c, false, "montmul", ISA_mont_msk },
- { 0x0234, false, "montsqr", ISA_mont_msk },
- { 0x0238, false, "camellia", ISA_camellia_msk },
- { 0x024a, false, "ASIBlkInit", ISA_blk_init_msk },
- { 0x0284, false, "xmontmul", ISA_xmont_msk }, // NYI
- { 0x02e6, false, "pause_nsec", ISA_pause_nsec_msk }, // NYI
-
- { 0x0000, false, NULL, 0 }
- };
-
- CPUinfo caps("cpucaps"); // Read "cpucaps" from /proc/cpuinfo.
-
- assert(caps.valid(), "must be");
-
- _features = parse_features(s_feature_tbl, caps.value());
-
- assert(has_v9(), "must be"); // Basic SPARC-V9 required (V8 not supported).
-
- CPUinfo type("type");
-
- bool is_sun4v = type.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+
- bool is_sun4u = type.match("sun4u"); // All other Fujitsu
-
- uint64_t synthetic = 0;
-
- if (is_sun4v) {
- // Indirect and direct branches are equally fast.
- synthetic = CPU_fast_ind_br_msk;
- // Fast IDIV, BIS and LD available on Niagara Plus.
- if (has_vis2()) {
- synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk);
- // ...on Core C4 however, we prefer not to use BIS.
- if (!has_sparc5()) {
- synthetic |= CPU_fast_bis_msk;
- }
- }
- // Niagara Core C3 supports fast RDPC and block zeroing.
- if (has_ima()) {
- synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk);
- }
- // Niagara Core C3 and C4 have slow CMOVE.
- if (!has_ima()) {
- synthetic |= CPU_fast_cmove_msk;
- }
- } else if (is_sun4u) {
- // SPARC64 only have fast IDIV and RDPC.
- synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk);
- } else {
- log_info(os, cpu)("Unable to derive CPU features: %s", type.value());
- }
-
- _features += synthetic; // Including CPU derived/synthetic features.
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-static uint32_t uhash32(const char name[]);
-
-static void update_table(FeatureEntry feature_tbl[], uint32_t hv,
- const char* ch1p,
- const char* endp);
-
-/* Given a feature table, parse the input text holding the string value of
- * 'cpucaps' as reported by '/proc/cpuinfo', in order to complete the table
- * with information on each admissible feature (whether present or not).
- *
- * Return the composite bit-mask representing the features found.
- */
-static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]) {
- log_info(os, cpu)("Parse CPU features: %s\n", input);
-
-#ifdef ASSERT
- // Verify that hash value entries in the table are unique and ordered.
-
- uint32_t prev = 0;
-
- for (uint k = 0; feature_tbl[k].name != NULL; k++) {
- feature_tbl[k].seen = false;
-
- assert(feature_tbl[k].hash == uhash32(feature_tbl[k].name),
- "feature '%s' has mismatching hash 0x%08x (expected 0x%08x).\n",
- feature_tbl[k].name,
- feature_tbl[k].hash,
- uhash32(feature_tbl[k].name));
-
- assert(prev < feature_tbl[k].hash,
- "feature '%s' has invalid hash 0x%08x (previous is 0x%08x).\n",
- feature_tbl[k].name,
- feature_tbl[k].hash,
- prev);
-
- prev = feature_tbl[k].hash;
- }
-#endif
- // Identify features from the input, consisting of a string with features
- // separated by commas (or whitespace), e.g. "flush,muldiv,v9,mul32,div32,
- // v8plus,popc,vis".
-
- uint32_t hv = 0;
- const char* ch1p = &input[0];
- uint i = 0;
-
- do {
- char ch = input[i];
-
- if (isalnum(ch) || ch == '_') {
- hv += (ch - 32u);
- }
- else if (isspace(ch) || ch == ',' || ch == '\0') { // end-of-token
- if (ch1p < &input[i]) {
- update_table(feature_tbl, hv, ch1p, &input[i]);
- }
- ch1p = &input[i + 1]; hv = 0;
- } else {
- // Handle non-accepted input robustly.
- log_info(os, cpu)("Bad token in feature string: '%c' (0x%02x).\n", ch, ch);
- ch1p = &input[i + 1]; hv = 0;
- }
- }
- while (input[i++] != '\0');
-
- // Compute actual bit-mask representation.
-
- uint64_t mask = 0;
-
- for (uint k = 0; feature_tbl[k].name != NULL; k++) {
- mask |= feature_tbl[k].seen ? feature_tbl[k].mask : 0;
- }
-
- return mask;
-}
-
-static uint32_t uhash32(const char name[]) {
- uint32_t hv = 0;
-
- for (uint i = 0; name[i] != '\0'; i++) {
- hv += (name[i] - 32u);
- }
-
- return hv;
-}
-
-static bool verify_match(const char name[], const char* ch1p, const char* endp);
-
-static void update_table(FeatureEntry feature_tbl[], uint32_t hv, const char* ch1p, const char* endp) {
- assert(ch1p < endp, "at least one character");
-
- // Look for a hash value in the table. Since this table is a small one (and
- // is expected to stay small), we use a simple linear search (iff the table
- // grows large, we may consider to adopt a binary ditto, or a perfect hash).
-
- for (uint k = 0; feature_tbl[k].name != NULL; k++) {
- uint32_t hash = feature_tbl[k].hash;
-
- if (hash < hv) continue;
-
- if (hash == hv) {
- const char* name = feature_tbl[k].name;
-
- if (verify_match(name, ch1p, endp)) {
- feature_tbl[k].seen = true;
- break;
- }
- }
-
- // Either a non-matching feature (when hash == hv) or hash > hv. In either
- // case we break out of the loop and terminate the search (note that the
- // table is assumed to be uniquely sorted on the hash).
-
- break;
- }
-}
-
-static bool verify_match(const char name[], const char* ch1p, const char* endp) {
- size_t len = strlen(name);
-
- if (len != static_cast(endp - ch1p)) {
- return false;
- }
-
- for (uint i = 0; ch1p + i < endp; i++) {
- if (name[i] != ch1p[i]) return false;
- }
-
- return true;
-}
diff --git a/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp b/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp
index e6b85a40791..32346a0d063 100644
--- a/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp
+++ b/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -63,18 +63,7 @@ inline u4 Bytes::swap_u4(u4 x) {
#ifdef AMD64
inline u8 Bytes::swap_u8(u8 x) {
-#ifdef SPARC_WORKS
- // workaround for SunStudio12 CR6615391
- __asm__ __volatile__ (
- "bswapq %0"
- :"=r" (x) // output : register 0 => x
- :"0" (x) // input : x => register 0
- :"0" // clobbered register
- );
- return x;
-#else
return bswap_64(x);
-#endif
}
#else
// Helper function for swap_u8
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 ed7e0b8d3b6..fd441e61ed1 100644
--- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
+++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
@@ -95,13 +95,7 @@
#endif // AMD64
address os::current_stack_pointer() {
-#ifdef SPARC_WORKS
- void *esp;
- __asm__("mov %%" SPELL_REG_SP ", %0":"=r"(esp));
- return (address) ((char*)esp + sizeof(long)*2);
-#else
return (address)__builtin_frame_address(0);
-#endif
}
char* os::non_memory_address_word() {
@@ -224,10 +218,7 @@ frame os::get_sender_for_C_frame(frame* fr) {
}
intptr_t* _get_previous_fp() {
-#ifdef SPARC_WORKS
- intptr_t **ebp;
- __asm__("mov %%" SPELL_REG_FP ", %0":"=r"(ebp));
-#elif defined(__clang__)
+#if defined(__clang__)
intptr_t **ebp;
__asm__ __volatile__ ("mov %%" SPELL_REG_FP ", %0":"=r"(ebp):);
#else
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 5cf2ea744be..d431d96dda1 100644
--- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp
+++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp
@@ -86,14 +86,8 @@ char* os::non_memory_address_word() {
// Must never look like an address returned by reserve_memory,
// even in its subfields (as defined by the CPU immediate fields,
// if the CPU splits constants across multiple instructions).
-#ifdef SPARC
- // On SPARC, 0 != %hi(any real address), because there is no
- // allocation in the first 1Kb of the virtual address space.
- return (char *) 0;
-#else
// This is the value for x86; works pretty well for PPC too.
return (char *) -1;
-#endif // SPARC
}
address os::Linux::ucontext_get_pc(const ucontext_t* uc) {
diff --git a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp
deleted file mode 100644
index de82951663d..00000000000
--- a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP
-#define OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP
-
-// Implementation of class atomic
-
-// Implement ADD using a CAS loop.
-template
-struct Atomic::PlatformAdd {
- template
- inline D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const {
- D old_value = *dest;
- while (true) {
- D new_value = old_value + add_value;
- D result = cmpxchg(dest, old_value, new_value);
- if (result == old_value) break;
- old_value = result;
- }
- return old_value + add_value;
- }
-
- template
- inline D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const {
- return add_and_fetch(dest, add_value, order) - add_value;
- }
-};
-
-template<>
-template
-inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(4 == sizeof(T));
- __asm__ volatile ( "swap [%2],%0"
- : "=r" (exchange_value)
- : "0" (exchange_value), "r" (dest)
- : "memory");
- return exchange_value;
-}
-
-template<>
-template
-inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(T));
- T old_value = *dest;
- while (true) {
- T result = cmpxchg(dest, old_value, exchange_value);
- if (result == old_value) break;
- old_value = result;
- }
- return old_value;
-}
-
-// No direct support for cmpxchg of bytes; emulate using int.
-template<>
-struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
-
-template<>
-template
-inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest,
- T compare_value,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(4 == sizeof(T));
- T rv;
- __asm__ volatile(
- " cas [%2], %3, %0"
- : "=r" (rv)
- : "0" (exchange_value), "r" (dest), "r" (compare_value)
- : "memory");
- return rv;
-}
-
-template<>
-template
-inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest,
- T compare_value,
- T exchange_value,
- atomic_memory_order order) const {
- STATIC_ASSERT(8 == sizeof(T));
- T rv;
- __asm__ volatile(
- " casx [%2], %3, %0"
- : "=r" (rv)
- : "0" (exchange_value), "r" (dest), "r" (compare_value)
- : "memory");
- return rv;
-}
-
-#endif // OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP
diff --git a/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp
deleted file mode 100644
index 37544b0d26e..00000000000
--- a/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP
-#define OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP
-
-#include "utilities/globalDefinitions.hpp"
-
-inline unsigned count_trailing_zeros(uintx x) {
- assert(x != 0, "precondition");
- // Reduce to mask with ones in all positions below the least
- // significant set bit of x, and zeros otherwise.
- uintx rx = (x - 1) & ~x; // sub x, 1, rx; andn rx, x, rx;
- // Then count the set bits in the reduction.
- uintx result;
- __asm__(" popc %1, %0\n\t" : "=r" (result) : "r" (rx));
- return result;
-}
-
-#endif // OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP
diff --git a/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp
deleted file mode 100644
index 63d5221a165..00000000000
--- a/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP
-#define OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP
-
-//
-// Sets the default values for platform dependent flags used by the runtime system.
-// (see globals.hpp)
-//
-
-define_pd_global(size_t, JVMInvokeMethodSlack, 12288);
-
-// Used on 64 bit platforms for UseCompressedOops base address
-// use 6G as default base address because by default the OS maps the application
-// to 4G on Solaris-Sparc. This leaves at least 2G for the native heap.
-define_pd_global(size_t, HeapBaseMinAddress, CONST64(6)*G);
-
-
-
-#endif // OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP
diff --git a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp
deleted file mode 100644
index e5e7f152d5b..00000000000
--- a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP
-#define OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP
-
-// Included in orderAccess.hpp header file.
-
-// Compiler version last used for testing: solaris studio 12u3
-// Please update this information when this file changes
-
-// Implementation of class OrderAccess.
-
-// Assume TSO.
-
-// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions
-inline void compiler_barrier() {
- __asm__ volatile ("" : : : "memory");
-}
-
-inline void OrderAccess::loadload() { compiler_barrier(); }
-inline void OrderAccess::storestore() { compiler_barrier(); }
-inline void OrderAccess::loadstore() { compiler_barrier(); }
-inline void OrderAccess::storeload() { fence(); }
-
-inline void OrderAccess::acquire() { compiler_barrier(); }
-inline void OrderAccess::release() { compiler_barrier(); }
-
-inline void OrderAccess::fence() {
- __asm__ volatile ("membar #StoreLoad" : : : "memory");
-}
-
-inline void OrderAccess::cross_modify_fence() { }
-
-#endif // OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP
diff --git a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp
deleted file mode 100644
index b15a8e5e1fc..00000000000
--- a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp
+++ /dev/null
@@ -1,727 +0,0 @@
-/*
- * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-// no precompiled headers
-#include "jvm.h"
-#include "asm/macroAssembler.hpp"
-#include "macroAssembler_sparc.hpp"
-#include "classfile/classLoader.hpp"
-#include "classfile/systemDictionary.hpp"
-#include "classfile/vmSymbols.hpp"
-#include "code/codeCache.hpp"
-#include "code/icBuffer.hpp"
-#include "code/vtableStubs.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/allocation.inline.hpp"
-#include "nativeInst_sparc.hpp"
-#include "os_share_solaris.hpp"
-#include "prims/jniFastGetField.hpp"
-#include "prims/jvm_misc.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/extendedPC.hpp"
-#include "runtime/frame.inline.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/java.hpp"
-#include "runtime/javaCalls.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/osThread.hpp"
-#include "runtime/safepointMechanism.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/timer.hpp"
-#include "utilities/events.hpp"
-#include "utilities/vmError.hpp"
-
-# include